]> Kevux Git Server - fll/commitdiff
Progress: controller program and other changes.
authorKevin Day <thekevinday@gmail.com>
Sat, 26 Dec 2020 03:39:17 +0000 (21:39 -0600)
committerKevin Day <thekevinday@gmail.com>
Sat, 26 Dec 2020 03:39:17 +0000 (21:39 -0600)
Lots of changes with the most notable described below.

This adds support for capabilities, which depends on the external libcap (-lcap).
This introduces a problem because it is POSIX complaint in the sense of a draft and Linux has adopted it.
The end result is that instead of being in libc, the functions are defined in libcap.
To address this complication, a new project f_capability, is added to conditional compile in support and otherwise provide stubs.
This allows the rest of the projects to just call the f_capability functions without needing as many macros.
A define macro is still needed and the appropriate libary (-lcap) is still needed (or not if disabled).

I have further observed that when adding -lcap, the ar progam's ficklness on the order becomes a problem.
As a temporary work around, I am appending the "build_libraries" after all libaries introduced by a mode.

55 files changed:
build/level_0/settings
build/level_2/settings
build/monolithic/settings
build/scripts/bootstrap-example.sh
build/scripts/bootstrap.sh
level_0/f_account/c/account.c
level_0/f_account/c/account.h
level_0/f_capability/c/capability-common.h [new file with mode: 0644]
level_0/f_capability/c/capability.c [new file with mode: 0644]
level_0/f_capability/c/capability.h [new file with mode: 0644]
level_0/f_capability/data/build/defines [new file with mode: 0644]
level_0/f_capability/data/build/dependencies [new file with mode: 0644]
level_0/f_capability/data/build/settings [new file with mode: 0644]
level_0/f_status/c/status.h
level_1/fl_conversion/c/conversion.c
level_1/fl_execute/c/execute-common.h
level_1/fl_execute/c/execute.h
level_1/fl_execute/data/build/defines
level_1/fl_execute/data/build/dependencies
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.h
level_2/fll_execute/c/private-execute.c
level_2/fll_execute/c/private-execute.h
level_2/fll_execute/data/build/defines
level_2/fll_execute/data/build/dependencies
level_2/fll_execute/data/build/settings
level_2/fll_status/c/status.c
level_3/controller/c/controller.c
level_3/controller/c/controller.h
level_3/controller/c/private-common.h
level_3/controller/c/private-controller.c
level_3/controller/c/private-controller.h
level_3/controller/c/private-rule.c
level_3/controller/c/private-rule.h
level_3/controller/data/build/defines
level_3/controller/data/build/dependencies
level_3/controller/data/build/settings
level_3/controller/data/settings/example/rules/command/multiple.rule
level_3/controller/data/settings/rules/program/terminal.rule
level_3/controller/data/settings/rules/service/dbus.rule
level_3/controller/data/settings/rules/service/logger.rule
level_3/controller/data/settings/rules/service/mouse.rule
level_3/controller/data/settings/rules/task/clock.rule
level_3/controller/data/settings/rules/task/keyboard.rule
level_3/controller/documents/rule.txt
level_3/controller/specifications/rule.txt
level_3/fake/c/private-build.c
level_3/fake/data/build/defines
level_3/fake/data/build/dependencies
level_3/fake/data/build/settings
level_3/firewall/data/build/defines
level_3/firewall/data/build/dependencies
level_3/firewall/data/build/settings

index d4b781bfb849effbc3dbca6566a13e4781723064..a59c5a705fe2a3b7313e6edb43e7fade040aecd9 100644 (file)
@@ -18,11 +18,11 @@ modes_default level
 build_compiler gcc
 build_indexer ar
 build_language c
-build_libraries -lc
+build_libraries -lc -lcap
 build_libraries-level
-build_sources_library account.c console.c conversion.c directory.c private-directory.c environment.c private-environment.c file.c private-file.c fss.c iki.c private-iki.c memory.c path.c private-path.c pipe.c print.c private-print.c process.c serialize.c private-serialize.c signal.c socket.c utf.c private-utf.c
+build_sources_library account.c capability.c console.c conversion.c directory.c private-directory.c environment.c private-environment.c file.c private-file.c fss.c iki.c private-iki.c memory.c path.c private-path.c pipe.c print.c private-print.c process.c serialize.c private-serialize.c signal.c socket.c utf.c private-utf.c
 build_sources_program
-build_sources_headers account.h account-common.h color.h console.h console-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 memory.h memory_structure.h path.h path-common.h pipe.h print.h process.h process-common.h serialize.h serialize-common.h signal.h signal-common.h socket.h socket-common.h status.h status_array.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 utf.h utf-common.h
+build_sources_headers account.h account-common.h capability.h capability-common.h color.h console.h console-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 memory.h memory_structure.h path.h path-common.h pipe.h print.h process.h process-common.h serialize.h serialize-common.h signal.h signal-common.h socket.h socket-common.h status.h status_array.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 utf.h utf-common.h
 build_sources_script
 build_sources_setting
 build_script yes
@@ -42,6 +42,7 @@ search_exclusive yes
 search_shared yes
 search_static yes
 
+#defines_all -D_di_libcap_
 defines_all
 defines_static
 defines_shared
index 2a0b0c9e26ec58c71b6290682878fc7187f5a55d..d63d28aa2c5e4470be31a7b0e1e3883fbe8132ce 100644 (file)
@@ -18,7 +18,7 @@ modes_default level
 build_compiler gcc
 build_indexer ar
 build_language c
-build_libraries -lc
+build_libraries -lc -lcap
 build_libraries-level -lfll_1 -lfll_0
 build_sources_library environment.c error.c private-error.c execute.c private-execute.c file.c private-file.c fss.c private-fss.c fss_basic.c fss_basic_list.c fss_embedded_list.c fss_extended.c fss_extended_list.c fss_status.c iki.c private-iki.c path.c program.c status.c
 build_sources_program
@@ -42,6 +42,7 @@ search_exclusive yes
 search_shared yes
 search_static yes
 
+#defines_all -D_di_libcap_
 defines_all
 defines_static
 defines_shared
index 3b2844fd4ac098558fa53e470a0d726bbf5be940..44bb2c4c4c6357e5760624a64297381cbe0b4221 100644 (file)
@@ -18,11 +18,11 @@ modes_default monolithic
 build_compiler gcc
 build_indexer ar
 build_language c
-build_libraries -lc
+build_libraries -lc -lcap
 build_libraries-monolithic
-build_sources_library level_0/account.c level_0/console.c level_0/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/private-file.c level_0/fss.c level_0/iki.c level_0/private-iki.c level_0/memory.c level_0/path.c level_0/private-path.c level_0/pipe.c level_0/print.c level_0/private-print.c level_0/process.c level_0/serialize.c level_0/private-serialize.c level_0/signal.c level_0/socket.c level_0/utf.c level_0/private-utf.c level_1/color.c level_1/console.c level_1/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/status.c level_1/string.c level_1/private-string.c level_1/type.c level_1/private-type.c level_1/utf.c level_1/private-utf.c level_1/utf_file.c level_1/private-utf_file.c level_2/environment.c level_2/error.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/program.c level_2/status.c
+build_sources_library level_0/account.c level_0/capability.c level_0/console.c level_0/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/private-file.c level_0/fss.c level_0/iki.c level_0/private-iki.c level_0/memory.c level_0/path.c level_0/private-path.c level_0/pipe.c level_0/print.c level_0/private-print.c level_0/process.c level_0/serialize.c level_0/private-serialize.c level_0/signal.c level_0/socket.c level_0/utf.c level_0/private-utf.c level_1/color.c level_1/console.c level_1/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/status.c level_1/string.c level_1/private-string.c level_1/type.c level_1/private-type.c level_1/utf.c level_1/private-utf.c level_1/utf_file.c level_1/private-utf_file.c level_2/environment.c level_2/error.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/program.c level_2/status.c
 build_sources_program
-build_sources_headers level_0/account.h level_0/account-common.h level_0/color.h level_0/console.h level_0/console-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/memory.h level_0/memory_structure.h level_0/path.h level_0/path-common.h level_0/pipe.h level_0/print.h level_0/process.h level_0/process-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/status_array.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/utf.h level_0/utf-common.h level_1/color.h level_1/console.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/status.h level_1/string.h level_1/type.h level_1/utf.h level_1/utf_file.h level_2/environment.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/program.h level_2/status.h
+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/console.h level_0/console-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/memory.h level_0/memory_structure.h level_0/path.h level_0/path-common.h level_0/pipe.h level_0/print.h level_0/process.h level_0/process-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/status_array.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/utf.h level_0/utf-common.h level_1/color.h level_1/console.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/status.h level_1/string.h level_1/type.h level_1/utf.h level_1/utf_file.h level_2/environment.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/program.h level_2/status.h
 build_sources_script
 build_sources_setting
 build_script yes
@@ -42,6 +42,7 @@ search_exclusive yes
 search_shared yes
 search_static yes
 
+#defines_all -D_di_libcap_
 defines_all
 defines_static
 defines_shared
index 998e1f9e1c14eb6cc10df3843f8219bdc34ba827..7d5593dbfa3b25596a42c2e63240ef0fd90ad25f 100644 (file)
@@ -41,7 +41,7 @@ if [[ $1 == "individual" ]] ; then
   bash build/scripts/package.sh $verbose $color build -i
 
   if [[ $? -eq 0 ]] ; then
-    for i in f_type f_status f_memory f_string f_utf f_account f_color f_console f_conversion f_directory f_environment f_execute f_file f_fss f_iki f_path f_pipe f_print f_process f_serialize f_signal f_socket fl_color fl_console fl_conversion fl_directory fl_environment fl_execute fl_fss fl_iki fl_print fl_status fl_string fl_type fl_utf fl_utf_file fll_environment fll_error fll_execute fll_file fll_fss fll_iki fll_path fll_program fll_status ; do
+    for i in f_type f_status f_memory f_string f_utf f_account f_capability f_color f_console f_conversion f_directory f_environment f_execute f_file f_fss f_iki f_path f_pipe f_print f_process f_serialize f_signal f_socket fl_color fl_console fl_conversion fl_directory fl_environment fl_execute fl_fss fl_iki fl_print fl_status fl_string fl_type fl_utf fl_utf_file fll_environment fll_error fll_execute fll_file fll_fss fll_iki fll_path fll_program fll_status ; do
       echo && echo "Processing $i." &&
 
       cd package/individual/$i-$2/ &&
index 792b43e8068bd9be1e37bb1f334153f333bcacaf..1b43ef7f815659d0b7d22e3d55d8f004d41e9601 100644 (file)
@@ -623,7 +623,7 @@ bootstrap_operation_build() {
   if [[ $libraries == "" ]] ; then
     libraries=${variables[$(bootstrap_id build_libraries-$mode)]}
   else
-    libraries="$libraries ${variables[$(bootstrap_id build_libraries-$mode)]}"
+    libraries="${variables[$(bootstrap_id build_libraries-$mode)]} $libraries"
   fi
 
   if [[ $defines == "" ]] ; then
index 88dd2bdf8aad282f5f007210ed9697c9f29d88bd..86149d1eba50073000c07c09d288a68d3edbaa2c 100644 (file)
@@ -6,6 +6,10 @@ extern "C" {
 
 #ifndef _di_f_account_id_group_by_name_
   f_return_status f_account_id_group_by_name(const f_string_t name, gid_t *id) {
+    #ifndef _di_level_0_parameter_checking_
+      if (!id) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
     f_status_t status = F_none;
 
     const size_t length_max = sysconf(_SC_GETPW_R_SIZE_MAX);
@@ -81,13 +85,17 @@ extern "C" {
 
 #ifndef _di_f_account_id_user_by_name_
   f_return_status f_account_id_user_by_name(const f_string_t name, uid_t *id) {
+    #ifndef _di_level_0_parameter_checking_
+      if (!id) return F_status_set_error(F_parameter);
+    #endif // _di_level_0_parameter_checking_
+
     f_status_t status = F_none;
 
     const size_t length_max = sysconf(_SC_GETPW_R_SIZE_MAX);
 
     // note: pointer seems pointless except that it is used to determine if the name was found.
     struct passwd password;
-    struct passwd *pointer;
+    struct passwd *pointer = 0;
 
     size_t length = length_max;
 
index 7f8ba684cfd086353902715cdab209e420970d4b..9be5caad249f8a00e21f03ef65bdc132b2af025d 100644 (file)
@@ -37,6 +37,7 @@ extern "C" {
  *
  * @param name
  *   The group name.
+ *   The name must be NULL terminated.
  * @param id
  *   The id associated with the given name.
  *
@@ -50,7 +51,7 @@ extern "C" {
  *   F_interrupt (with error bit) when program received an interrupt signal, halting operation.
  *   F_memory_not (with error bit) if out of memory.
  *   F_parameter (with error bit) if a parameter is invalid.
- *   F_failure (with error bit) on any other failure.
+ *   F_failure (with error bit) on any other error.
  *
  * @see getgrnam_r()
  */
@@ -63,6 +64,7 @@ extern "C" {
  *
  * @param name
  *   The user name.
+ *   The name must be NULL terminated.
  * @param id
  *   The id associated with the given name.
  *
@@ -76,7 +78,7 @@ extern "C" {
  *   F_interrupt (with error bit) when program received an interrupt signal, halting operation.
  *   F_memory_not (with error bit) if out of memory.
  *   F_parameter (with error bit) if a parameter is invalid.
- *   F_failure (with error bit) on any other failure.
+ *   F_failure (with error bit) on any other error.
  *
  * @see getpwnam_r()
  */
diff --git a/level_0/f_capability/c/capability-common.h b/level_0/f_capability/c/capability-common.h
new file mode 100644 (file)
index 0000000..599ff22
--- /dev/null
@@ -0,0 +1,58 @@
+/**
+ * FLL - Level 0
+ *
+ * Project: Capability
+ * API Version: 0.5
+ * Licenses: lgplv2.1
+ *
+ * Defines common data to be used for/by capability related functionality.
+ *
+ * This is auto-included by account.h and should not need to be explicitly included.
+ */
+#ifndef _F_capability_common_h
+#define _F_capability_common_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Provide a typedef of cap_t such that if _di_libcap_ is defined then a stub is used in its place.
+ */
+#ifndef _di_f_capability_t_
+
+  enum {
+    f_capability_value_type_effective = 0,
+    f_capability_value_type_permitted,
+    f_capability_value_type_inheritable,
+  };
+
+  enum {
+    f_capability_flag_type_clear = 0,
+    f_capability_flag_type_set,
+  };
+
+  // provide stubs in the event that libcap is disabled.
+  #ifdef _di_libcap_
+    typedef void * cap_t;
+    typedef int cap_value_t;
+    typedef int cap_flag_t;
+    typedef int cap_flag_value_t;
+  #endif // _di_libcap_
+
+  typedef cap_t f_capability_t;
+  typedef cap_value_t f_capability_value_t;
+  typedef cap_flag_t f_capability_flag_t;
+  typedef cap_flag_value_t f_capability_flag_value_t;
+
+  #define f_capability_t_initialize 0
+  #define f_capability_value_t_initialize 0
+  #define f_capability_flag_t_initialize 0
+  #define f_capability_flag_value_t_initialize 0
+#endif // _di_f_capability_t_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _F_capability_common_h
diff --git a/level_0/f_capability/c/capability.c b/level_0/f_capability/c/capability.c
new file mode 100644 (file)
index 0000000..a222cf2
--- /dev/null
@@ -0,0 +1,501 @@
+#include "capability.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef _di_libcap_
+
+  #ifndef _di_f_capability_clear_
+    f_return_status f_capability_clear(f_capability_t *capability) {
+      return F_status_set_error(F_supported_not);
+    }
+  #endif // _di_f_capability_clear_
+
+  #ifndef _di_f_capability_clear_flag_
+    f_return_status f_capability_clear_flag(const f_capability_flag_t flag, f_capability_t *capability) {
+      return F_status_set_error(F_supported_not);
+    }
+  #endif // _di_f_capability_clear_flag_
+
+  #ifndef _di_f_capability_compare_
+    f_return_status f_capability_compare(const f_capability_t capability1, const f_capability_t capability2, int *flags) {
+      return F_status_set_error(F_supported_not);
+    }
+  #endif // _di_f_capability_compare_
+
+  #ifndef _di_f_capability_delete_
+    f_return_status f_capability_delete(f_capability_t *capability) {
+      return F_status_set_error(F_supported_not);
+    }
+  #endif // _di_f_capability_delete_
+
+  #ifndef _di_f_capability_duplicate_
+    f_return_status f_capability_duplicate(const f_capability_t source, f_capability_t *destination) {
+      #ifndef _di_level_0_parameter_checking_
+        if (!destination) return F_status_set_error(F_parameter);
+      #endif // _di_level_0_parameter_checking_
+
+      return F_status_set_error(F_supported_not);
+    }
+  #endif // _di_f_capability_duplicate_
+
+  #ifndef _di_f_capability_flag_get_
+    f_return_status f_capability_flag_get(const f_capability_t capability, const f_capability_value_t code, const f_capability_flag_t flag, f_capability_flag_value_t *enabled) {
+      return F_status_set_error(F_supported_not);
+    }
+  #endif // _di_f_capability_flag_get_
+
+  #ifndef _di_f_capability_flag_set_
+    f_return_status f_capability_flag_set(const f_capability_flag_t flag, const f_capability_flag_value_t enabled, const f_int32s_t codes, f_capability_t *capability) {
+      return F_status_set_error(F_supported_not);
+    }
+  #endif // _di_f_capability_flag_set_
+
+  #ifndef _di_f_capability_from_name_
+    f_return_status f_capability_from_name(const f_string_t name, f_capability_value_t *code) {
+      return F_status_set_error(F_supported_not);
+    }
+  #endif // _di_f_capability_from_name_
+
+  #ifndef _di_f_capability_from_text_
+    f_return_status f_capability_from_text(const f_string_t text, f_capability_t *capability) {
+      return F_status_set_error(F_supported_not);
+    }
+  #endif // _di_f_capability_from_text_
+
+  #ifndef _di_f_capability_process_bound_drop_
+    f_return_status f_capability_process_bound_drop(f_capability_value_t code, int *bound) {
+      #ifndef _di_level_0_parameter_checking_
+        if (!bound) return F_status_set_error(F_parameter);
+      #endif // _di_level_0_parameter_checking_
+
+      return F_status_set_error(F_supported_not);
+    }
+  #endif // _di_f_capability_process_bound_drop_
+
+  #ifndef _di_f_capability_process_bound_get_
+    f_return_status f_capability_process_bound_get(f_capability_value_t code, int *bound) {
+      #ifndef _di_level_0_parameter_checking_
+        if (!bound) return F_status_set_error(F_parameter);
+      #endif // _di_level_0_parameter_checking_
+
+      return F_status_set_error(F_supported_not);
+    }
+  #endif // _di_f_capability_process_bound_get_
+
+  #ifndef _di_f_capability_initialize_
+    f_return_status f_capability_initialize(f_capability_t *capability) {
+      #ifndef _di_level_0_parameter_checking_
+        if (!capability) return F_status_set_error(F_parameter);
+      #endif // _di_level_0_parameter_checking_
+
+      return F_status_set_error(F_supported_not);
+    }
+  #endif // _di_f_capability_initialize_
+
+  #ifndef _di_f_capability_process_get_
+    f_return_status f_capability_process_get(f_capability_t *capability) {
+      #ifndef _di_level_0_parameter_checking_
+        if (!capability) return F_status_set_error(F_parameter);
+      #endif // _di_level_0_parameter_checking_
+
+      return F_status_set_error(F_supported_not);
+    }
+  #endif // _di_f_capability_process_get_
+
+  #ifndef _di_f_capability_process_get_by_id_
+    f_return_status f_capability_process_get_by_id(const pid_t id, f_capability_t *capability) {
+      #ifndef _di_level_0_parameter_checking_
+        if (!capability) return F_status_set_error(F_parameter);
+      #endif // _di_level_0_parameter_checking_
+
+      return F_status_set_error(F_supported_not);
+    }
+  #endif // _di_f_capability_process_get_by_id_
+
+  #ifndef _di_f_capability_process_set_
+    f_return_status f_capability_process_set(const f_capability_t capability) {
+      return F_status_set_error(F_supported_not);
+    }
+  #endif // _di_f_capability_process_set_
+
+  #ifndef _di_f_capability_supported_
+    bool f_capability_supported() {
+      return F_false;
+    }
+  #endif // _di_f_capability_supported_
+
+  #ifndef _di_f_capability_supported_code_
+    bool f_capability_supported_code(const f_capability_value_t code) {
+      return F_false;
+    }
+  #endif // _di_f_capability_supported_code_
+
+  #ifndef _di_f_capability_to_name_
+    f_return_status f_capability_to_name(const int code, f_string_dynamic_t *name) {
+      #ifndef _di_level_0_parameter_checking_
+        if (!name) return F_status_set_error(F_parameter);
+      #endif // _di_level_0_parameter_checking_
+
+      return F_status_set_error(F_supported_not);
+    }
+  #endif // _di_f_capability_to_name_
+
+  #ifndef _di_f_capability_to_text_
+    f_return_status f_capability_to_text(const f_capability_t capability, f_string_dynamic_t *text) {
+      return F_status_set_error(F_supported_not);
+    }
+  #endif // _di_f_capability_to_text_
+
+#else // _di_libcap_
+
+  #ifndef _di_f_capability_clear_
+    f_return_status f_capability_clear(f_capability_t *capability) {
+
+      if (cap_clear(*capability) < 0) {
+        if (errno == EINVAL) return F_status_set_error(F_parameter);
+
+        return F_status_set_error(F_failure);
+      }
+
+      return F_none;
+    }
+  #endif // _di_f_capability_clear_
+
+  #ifndef _di_f_capability_clear_flag_
+    f_return_status f_capability_clear_flag(const f_capability_flag_t flag, f_capability_t *capability) {
+
+      if (cap_clear_flag(*capability, flag) < 0) {
+        if (errno == EINVAL) return F_status_set_error(F_parameter);
+
+        return F_status_set_error(F_failure);
+      }
+
+      return F_none;
+    }
+  #endif // _di_f_capability_clear_flag_
+
+  #ifndef _di_f_capability_compare_
+    f_return_status f_capability_compare(const f_capability_t capability1, const f_capability_t capability2, int *flags) {
+
+      if (*flags) {
+        *flags = 0;
+      }
+
+      const int result = cap_compare(capability1, capability2);
+
+      if (result < 0) {
+        if (errno == EINVAL) return F_status_set_error(F_parameter);
+
+        return F_status_set_error(F_failure);
+      }
+
+      if (result) {
+        if (*flags) {
+          *flags = result;
+        }
+
+        return F_equal_to_not;
+      }
+
+      return F_equal_to;
+    }
+  #endif // _di_f_capability_compare_
+
+  #ifndef _di_f_capability_delete_
+    f_return_status f_capability_delete(f_capability_t *capability) {
+
+      if (cap_free(*capability) < 0) {
+        return F_status_set_error(F_failure);
+      }
+
+      *capability = 0;
+
+      return F_none;
+    }
+  #endif // _di_f_capability_delete_
+
+  #ifndef _di_f_capability_duplicate_
+    f_return_status f_capability_duplicate(const f_capability_t source, f_capability_t *destination) {
+      #ifndef _di_level_0_parameter_checking_
+        if (!destination) return F_status_set_error(F_parameter);
+      #endif // _di_level_0_parameter_checking_
+
+      *destination = cap_dup(source);
+
+      if (*destination) {
+        return F_none;
+      }
+
+      if (errno == EINVAL) return F_status_set_error(F_parameter);
+      if (errno == ENOMEM) return F_status_set_error(F_memory_not);
+
+      return F_status_set_error(F_failure);
+    }
+  #endif // _di_f_capability_duplicate_
+
+  #ifndef _di_f_capability_flag_get_
+    f_return_status f_capability_flag_get(const f_capability_t capability, const f_capability_value_t code, const f_capability_flag_t flag, f_capability_flag_value_t *enabled) {
+      #ifndef _di_level_0_parameter_checking_
+        if (!enabled) return F_status_set_error(F_parameter);
+      #endif // _di_level_0_parameter_checking_
+
+      if (cap_get_flag(capability, code, flag, enabled) < 0) {
+        if (errno == EINVAL) return F_status_set_error(F_parameter);
+
+        return F_status_set_error(F_failure);
+      }
+
+      return F_none;
+    }
+  #endif // _di_f_capability_flag_get_
+
+  #ifndef _di_f_capability_flag_set_
+    f_return_status f_capability_flag_set(const f_capability_flag_t flag, const f_capability_flag_value_t enabled, const f_int32s_t codes, f_capability_t *capability) {
+
+      if (cap_set_flag(*capability, flag, codes.used, codes.array, enabled) < 0) {
+        if (errno == EINVAL) return F_status_set_error(F_parameter);
+
+        return F_status_set_error(F_failure);
+      }
+
+      return F_none;
+    }
+  #endif // _di_f_capability_flag_set_
+
+  #ifndef _di_f_capability_from_name_
+    f_return_status f_capability_from_name(const f_string_t name, f_capability_value_t *code) {
+
+      if (cap_from_name(name, code) < 0) {
+        if (errno == EINVAL) return F_status_set_error(F_parameter);
+        if (errno == ENOMEM) return F_status_set_error(F_memory_not);
+
+        return F_status_set_error(F_failure);
+      }
+
+      return F_none;
+    }
+  #endif // _di_f_capability_from_name_
+
+  #ifndef _di_f_capability_from_text_
+    f_return_status f_capability_from_text(const f_string_t text, f_capability_t *capability) {
+      *capability = cap_from_text(text);
+
+      if (*capability) {
+        return F_none;
+      }
+
+      if (errno == EINVAL) return F_status_set_error(F_parameter);
+      if (errno == ENOMEM) return F_status_set_error(F_memory_not);
+
+      return F_status_set_error(F_failure);
+    }
+  #endif // _di_f_capability_from_text_
+
+  #ifndef _di_f_capability_initialize_
+    f_return_status f_capability_initialize(f_capability_t *capability) {
+      #ifndef _di_level_0_parameter_checking_
+        if (!capability) return F_status_set_error(F_parameter);
+      #endif // _di_level_0_parameter_checking_
+
+      *capability = cap_init();
+
+      if (*capability) {
+        return F_none;
+      }
+
+      if (errno == EINVAL) return F_status_set_error(F_parameter);
+      if (errno == ENOMEM) return F_status_set_error(F_memory_not);
+
+      return F_status_set_error(F_failure);
+    }
+  #endif // _di_f_capability_initialize_
+
+  #ifndef _di_f_capability_process_bound_drop_
+    f_return_status f_capability_process_bound_drop(f_capability_value_t code, int *bound) {
+
+      *bound = cap_drop_bound(code);
+
+      if (*bound < 0) {
+        return F_known_not;
+      }
+
+      if (*bound) {
+        return F_none;
+      }
+
+      return F_supported_not;
+    }
+  #endif // _di_f_capability_process_bound_drop_
+
+  #ifndef _di_f_capability_process_bound_get_
+    f_return_status f_capability_process_bound_get(f_capability_value_t code, int *bound) {
+      #ifndef _di_level_0_parameter_checking_
+        if (!bound) return F_status_set_error(F_parameter);
+      #endif // _di_level_0_parameter_checking_
+
+      *bound = cap_get_bound(code);
+
+      if (*bound < 0) {
+        return F_known_not;
+      }
+
+      if (*bound) {
+        return F_none;
+      }
+
+      return F_supported_not;
+    }
+  #endif // _di_f_capability_process_bound_get_
+
+  #ifndef _di_f_capability_process_get_
+    f_return_status f_capability_process_get(f_capability_t *capability) {
+
+      *capability = cap_get_proc();
+
+      if (*capability) {
+        return F_none;
+      }
+
+      if (errno == EINVAL) return F_status_set_error(F_parameter);
+      if (errno == ENOMEM) return F_status_set_error(F_memory_not);
+
+      return F_status_set_error(F_failure);
+    }
+  #endif // _di_f_capability_process_get_
+
+  #ifndef _di_f_capability_process_get_by_id_
+    f_return_status f_capability_process_get_by_id(const pid_t id, f_capability_t *capability) {
+
+      *capability = cap_get_pid(id);
+
+      if (*capability) {
+        return F_none;
+      }
+
+      if (errno == EINVAL) return F_status_set_error(F_parameter);
+      if (errno == ENOMEM) return F_status_set_error(F_memory_not);
+
+      return F_status_set_error(F_failure);
+    }
+  #endif // _di_f_capability_process_get_by_id_
+
+  #ifndef _di_f_capability_process_set_
+    f_return_status f_capability_process_set(const f_capability_t capability) {
+
+      if (cap_set_proc(capability) < 0) {
+        if (errno == EINVAL) return F_status_set_error(F_parameter);
+        if (errno == ENOMEM) return F_status_set_error(F_memory_not);
+        if (errno == EPERM) return F_status_set_error(F_prohibited);
+
+        return F_status_set_error(F_failure);
+      }
+
+      return F_none;
+    }
+  #endif // _di_f_capability_process_set_
+
+  #ifndef _di_f_capability_supported_
+    bool f_capability_supported() {
+      return F_true;
+    }
+  #endif // _di_f_capability_supported_
+
+  #ifndef _di_f_capability_supported_code_
+    bool f_capability_supported_code(const f_capability_value_t code) {
+      return CAP_IS_SUPPORTED(code);
+    }
+  #endif // _di_f_capability_supported_code_
+
+  #ifndef _di_f_capability_to_name_
+    f_return_status f_capability_to_name(const int code, f_string_dynamic_t *name) {
+      #ifndef _di_level_0_parameter_checking_
+        if (!name) return F_status_set_error(F_parameter);
+      #endif // _di_level_0_parameter_checking_
+
+      char *result = cap_to_name(code);
+
+      if (result) {
+        const f_string_length_t length = strlen(result);
+
+        f_status_t status = F_none;
+
+        if (name->used + length + 1 > name->size) {
+          if (name->used + length + 1 > f_string_length_t_size) {
+            return F_status_set_error(F_string_too_large);
+          }
+
+          f_macro_string_dynamic_t_resize(status, (*name), name->used + length + 1);
+
+          if (F_status_is_error(status)) {
+            cap_free(result);
+
+            return status;
+          }
+        }
+
+        memcpy(name->string + name->used, result, length);
+        name->used += length;
+        name->string[name->used] = 0;
+
+        cap_free(result);
+
+        return status;
+      }
+
+      if (errno == EINVAL) return F_status_set_error(F_parameter);
+      if (errno == ENOMEM) return F_status_set_error(F_memory_not);
+
+      return F_status_set_error(F_failure);
+    }
+  #endif // _di_f_capability_to_name_
+
+  #ifndef _di_f_capability_to_text_
+    f_return_status f_capability_to_text(const f_capability_t capability, f_string_dynamic_t *text) {
+      #ifndef _di_level_0_parameter_checking_
+        if (!text) return F_status_set_error(F_parameter);
+      #endif // _di_level_0_parameter_checking_
+
+      f_string_length_t length = 0;
+
+      char *result = cap_to_text(capability, &length);
+
+      if (result) {
+        f_status_t status = F_none;
+
+        if (text->used + length + 1> text->size) {
+          if (text->used + length + 1 > f_string_length_t_size) {
+            return F_status_set_error(F_string_too_large);
+          }
+
+          f_macro_string_dynamic_t_resize(status, (*text), text->used + length + 1);
+
+          if (F_status_is_error(status)) {
+            cap_free(result);
+
+            return status;
+          }
+        }
+
+        memcpy(text->string + text->used, result, length);
+        text->used += length;
+        text->string[text->used] = 0;
+
+        cap_free(result);
+
+        return status;
+      }
+
+      if (errno == EINVAL) return F_status_set_error(F_parameter);
+      if (errno == ENOMEM) return F_status_set_error(F_memory_not);
+
+      return F_status_set_error(F_failure);
+    }
+  #endif // _di_f_capability_to_text_
+
+#endif // _di_libcap_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/level_0/f_capability/c/capability.h b/level_0/f_capability/c/capability.h
new file mode 100644 (file)
index 0000000..a36c228
--- /dev/null
@@ -0,0 +1,450 @@
+/**
+ * FLL - Level 0
+ *
+ * Project: Capability
+ * API Version: 0.5
+ * Licenses: lgplv2.1
+ *
+ * Provides capability related functionality.
+ *
+ * Capabilities are POSIX compliant as of POSIX 1003.1e (as a draft).
+ * Because it is only in POSIX as a draft, they are available via libcap instead of libc.
+ * Special linking is necessary and this project provides a wrapper that makes capabilities easier to work with whether libcap (and therefore capabilities) is available or not.
+ *
+ * When _di_libcap_ is defined (-D_di_libcap_) then many of the structures and functions provided here are stubs.
+ * Compilations with _di_libcap_ will not be binary compatible with compilations without _di_libcap_.
+ */
+#ifndef _F_capability_h
+#define _F_capability_h
+
+// libc includes
+#include <string.h>
+#include <sys/types.h>
+
+#ifndef _di_libcap_
+  #include <sys/capability.h>
+#endif // _di_libcap_
+
+// fll-0 includes
+#include <level_0/type.h>
+#include <level_0/type_array.h>
+#include <level_0/status.h>
+#include <level_0/memory.h>
+#include <level_0/string.h>
+
+// fll-0 capability includes
+#include <level_0/capability-common.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Clear the capability structure.
+ *
+ * @param capability
+ *   The capability to clear.
+ *
+ * @return
+ *   F_none on success.
+ *   F_failure (with error bit) on failure to duplicate.
+ *   F_memory_not (with error bit) if a out of memory.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_supported_not (with error bit) if this function is not available (due to not having libcap support compiled in).
+ *
+ * @see cap_clear()
+ */
+#ifndef _di_f_capability_clear_
+  extern f_return_status f_capability_clear(f_capability_t *capability);
+#endif // _di_f_capability_clear_
+
+/**
+ * Clear the capability flag.
+ *
+ * @param flag
+ *   The flag to clear.
+ * @param capability
+ *   The capability to clear the flag of.
+ *
+ * @return
+ *   F_none on success.
+ *   F_failure (with error bit) on failure to duplicate.
+ *   F_memory_not (with error bit) if a out of memory.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_supported_not (with error bit) if this function is not available (due to not having libcap support compiled in).
+ *
+ * @see cap_clear_flag()
+ */
+#ifndef _di_f_capability_clear_flag_
+  extern f_return_status f_capability_clear_flag(const f_capability_flag_t flag, f_capability_t *capability);
+#endif // _di_f_capability_clear_flag_
+
+/**
+ * Compare two capability structures.
+ *
+ * @param capability1
+ *   The first capability to compare.
+ * @param capability2
+ *   The second capability to compare.
+ * @param flags
+ *   (optional) This represents which of the flags that differ on miss.
+ *   Set to NULL to not use.
+ *
+ * @return
+ *   F_equal_to on match.
+ *   F_equal_to_not on miss.
+ *   F_failure (with error bit) on failure to duplicate.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_supported_not (with error bit) if this function is not available (due to not having libcap support compiled in).
+ *
+ * @see cap_compare()
+ */
+#ifndef _di_f_capability_compare_
+  extern f_return_status f_capability_compare(const f_capability_t capability1, const f_capability_t capability2, int *flags);
+#endif // _di_f_capability_compare_
+
+/**
+ * Free the capability structure.
+ *
+ * @param capability
+ *   The capability to delete.
+ *
+ * @return
+ *   F_none on success.
+ *   F_failure (with error bit) on failure to free memory.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_supported_not (with error bit) if this function is not available (due to not having libcap support compiled in).
+ *
+ * @see cap_free()
+ */
+#ifndef _di_f_capability_delete_
+  extern f_return_status f_capability_delete(f_capability_t *capability);
+#endif // _di_f_capability_delete_
+
+/**
+ * Duplicate (copy) the capability structure.
+ *
+ * Be sure to call f_capability_delete() when finished.
+ *
+ * @param source
+ *   The capability to duplicate.
+ * @param destination
+ *   The capability to copy to.
+ *
+ * @return
+ *   F_none on success.
+ *   F_failure (with error bit) on failure to duplicate.
+ *   F_memory_not (with error bit) if a out of memory.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_supported_not (with error bit) if this function is not available (due to not having libcap support compiled in).
+ *
+ * @see cap_dup()
+ */
+#ifndef _di_f_capability_duplicate_
+  extern f_return_status f_capability_duplicate(const f_capability_t source, f_capability_t *destination);
+#endif // _di_f_capability_duplicate_
+
+/**
+ * Get the value of a flag from the capability structure.
+ *
+ * @param capability
+ *   The capability to get the code of.
+ * @param code
+ *   The capability code to get the flag of.
+ * @param flag
+ *   The flag of the capability code to get the value of.
+ * @param enabled
+ *   The determined capability code flag value.
+ *   This is TRUE when the flag is enabled and FALSE otherwise.
+ *
+ * @return
+ *   F_none on success.
+ *   F_failure (with error bit) on failure to free memory.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_supported_not (with error bit) if this function is not available (due to not having libcap support compiled in).
+ *
+ * @see cap_get_flag()
+ */
+#ifndef _di_f_capability_flag_get_
+  extern f_return_status f_capability_flag_get(const f_capability_t capability, const f_capability_value_t code, const f_capability_flag_t flag, f_capability_flag_value_t *enabled);
+#endif // _di_f_capability_flag_get
+
+/**
+ * Set the value of a flags from the capability structure.
+ *
+ * @param flag
+ *   The flag of the capability code to set the value of.
+ * @param enabled
+ *   The capability code flag value to set.
+ *   This is TRUE when the flag is enabled and FALSE otherwise.
+ * @param codes
+ *   An array of codes to set the capability flag value of.
+ * @param capability
+ *   The capability to set the flag of.
+ *
+ * @return
+ *   F_none on success.
+ *   F_failure (with error bit) on failure to free memory.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_supported_not (with error bit) if this function is not available (due to not having libcap support compiled in).
+ *
+ * @see cap_set_flag()
+ */
+#ifndef _di_f_capability_flag_set_
+  extern f_return_status f_capability_flag_set(const f_capability_flag_t flag, const f_capability_flag_value_t enabled, const f_int32s_t codes, f_capability_t *capability);
+#endif // _di_f_capability_flag_set_
+
+/**
+ * Get the capability code from the capability name.
+ *
+ * @param name
+ *   The name of the capability (must be all lower case).
+ * @param code
+ *   (optional) The determined code.
+ *   Set to NULL to not use.
+ *
+ * @return
+ *   F_none on success and name is known.
+ *   F_known_not on success and name is unknown (and no code is provided).
+ *   F_memory_not (with error bit) if a out of memory.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_supported_not (with error bit) if this function is not available (due to not having libcap support compiled in).
+ *
+ * @see cap_from_name()
+ */
+#ifndef _di_f_capability_from_name_
+  extern f_return_status f_capability_from_name(const f_string_t name, f_capability_value_t *code);
+#endif // _di_f_capability_from_name_
+
+/**
+ * Get the capability represented by the given string.
+ *
+ * @param text
+ *   The human-readable NULL terminated string representing the capabilities (such as "cap_chown+ep").
+ * @param capability
+ *   The determined capabilities.
+ *   This must be freed via f_capability_delete() when finished with it.
+ *
+ * @return
+ *   F_none on success.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_supported_not (with error bit) if this function is not available (due to not having libcap support compiled in).
+ *   F_failure (with error bit) on any other failure.
+ *
+ * @see cap_from_text()
+ */
+#ifndef _di_f_capability_from_text_
+  extern f_return_status f_capability_from_text(const f_string_t text, f_capability_t *capability);
+#endif // _di_f_capability_from_text_
+
+/**
+ * Initialize the capability structure.
+ *
+ * Be sure to call f_capability_delete() when finished.
+ *
+ * @param capability
+ *   The capability to initialize.
+ *
+ * @return
+ *   F_none on success.
+ *   F_failure (with error bit) on failure to initialize.
+ *   F_memory_not (with error bit) if a out of memory.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_supported_not (with error bit) if this function is not available (due to not having libcap support compiled in).
+ *
+ * @see cap_init()
+ */
+#ifndef _di_f_capability_initialize_
+  extern f_return_status f_capability_initialize(f_capability_t *capability);
+#endif // _di_f_capability_initialize_
+
+/**
+ * Drop the bound for the process.
+ *
+ * This will lower the specified bounding set capability if appropriate permission exist (the  prevailing  effective capability set must have a raised CAP_SETPCAP).
+ *
+ * @param code
+ *   The capability code to get the bound for.
+ * @param bound
+ *   The determined bound value.
+ *
+ * @return
+ *   F_none on success.
+ *   F_supported_not if the given code is not supported by the current system.
+ *   F_known_not (with error bit) if the code is unknown.
+ *   F_memory_not (with error bit) if a out of memory.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_supported_not (with error bit) if this function is not available (due to not having libcap support compiled in).
+ *   F_failure (with error bit) on any other error.
+ *
+ * @see cap_drop_bound()
+ */
+#ifndef _di_f_capability_process_bound_drop_
+  extern f_return_status f_capability_process_bound_drop(f_capability_value_t code, int *bound);
+#endif // _di_f_capability_process_bound_drop_
+
+/**
+ * Get the bound for the process.
+ *
+ * @param code
+ *   The capability code to get the bound for.
+ * @param bound
+ *   The determined bound value.
+ *
+ * @return
+ *   F_none on success.
+ *   F_supported_not if the given code is not supported by the current system.
+ *   F_known_not (with error bit) if the code is unknown.
+ *   F_memory_not (with error bit) if a out of memory.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_supported_not (with error bit) if this function is not available (due to not having libcap support compiled in).
+ *   F_failure (with error bit) on any other error.
+ *
+ * @see cap_get_bound()
+ */
+#ifndef _di_f_capability_process_bound_get_
+  extern f_return_status f_capability_process_bound_get(f_capability_value_t code, int *bound);
+#endif // _di_f_capability_process_bound_get_
+
+/**
+ * Get the capability for the current process.
+ *
+ * Be sure to call f_capability_delete() when finished.
+ *
+ * @param capability
+ *   The determined capability.
+ *
+ * @return
+ *   F_none on success.
+ *   F_memory_not (with error bit) if a out of memory.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_supported_not (with error bit) if this function is not available (due to not having libcap support compiled in).
+ *   F_failure (with error bit) on any other error.
+ *
+ * @see cap_get_proc()
+ */
+#ifndef _di_f_capability_process_get_
+  extern f_return_status f_capability_process_get(f_capability_t *capability);
+#endif // _di_f_capability_process_get_
+
+/**
+ * Get the capability for the process represented by the given PID.
+ *
+ * Be sure to call f_capability_delete() when finished.
+ *
+ * @param id
+ *   The process ID (pid) to get capabilities of.
+ * @param capability
+ *   The determined capability.
+ *
+ * @return
+ *   F_none on success.
+ *   F_memory_not (with error bit) if a out of memory.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_supported_not (with error bit) if this function is not available (due to not having libcap support compiled in).
+ *   F_failure (with error bit) on any other error.
+ *
+ * @see cap_get_pid()
+ */
+#ifndef _di_f_capability_process_get_by_id_
+  extern f_return_status f_capability_process_get_by_id(const pid_t id, f_capability_t *capability);
+#endif // _di_f_capability_process_get_by_id_
+
+/**
+ * Set the capability for the current process.
+ *
+ * @param capability
+ *   The capability to assign.
+ *
+ * @return
+ *   F_none on success.
+ *   F_memory_not (with error bit) if a out of memory.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_prohibited (with error bit) if system does not support a capability code specified.
+ *   F_supported_not (with error bit) if this function is not available (due to not having libcap support compiled in).
+ *   F_failure (with error bit) on any other error.
+ *
+ * @see cap_set_proc()
+ */
+#ifndef _di_f_capability_process_set_
+  extern f_return_status f_capability_process_set(const f_capability_t capability);
+#endif // _di_f_capability_process_set_
+
+/**
+ * Check if capabilities are supported.
+ *
+ * @return
+ *   TRUE if supported.
+ *   FALSE otherwise.
+ */
+#ifndef _di_f_capability_supported_
+  extern bool f_capability_supported();
+#endif // _di_f_capability_supported_
+
+/**
+ * Check if capabilities are supported.
+ *
+ * @param code
+ *   The capability code.
+ *
+ * @return
+ *   TRUE if the code is supported.
+ *   FALSE otherwise.
+ *
+ * @see CAP_IS_SUPPORTED()
+ */
+#ifndef _di_f_capability_supported_code_
+  extern bool f_capability_supported_code(f_capability_value_t code);
+#endif // _di_f_capability_supported_code_
+
+/**
+ * Convert the capability code to a name (string).
+ *
+ * @param code
+ *   The capability code.
+ * @param name
+ *   The determined name.
+ *   The name is appended into this variable.
+ *   This is not NULL terminated.
+ *
+ * @return
+ *   F_none on success.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_string_too_large (with error bit) if appended string length is too large to store in the buffer.
+ *   F_supported_not (with error bit) if this function is not available (due to not having libcap support compiled in).
+ *   F_failure (with error bit) on any other failure.
+ *
+ * @see cap_free()
+ * @see cap_to_name()
+ */
+#ifndef _di_f_capability_to_name_
+  extern f_return_status f_capability_to_name(const f_capability_value_t code, f_string_dynamic_t *name);
+#endif // _di_f_capability_to_name_
+
+/**
+ * Convert the capability to a human-readable NULL terminated string.
+ *
+ * @param capability
+ *   The capability code.
+ * @param text
+ *   The determined human-readable NULL terminated string.
+ *
+ * @return
+ *   F_none on success.
+ *   F_parameter (with error bit) if a parameter is invalid.
+ *   F_string_too_large (with error bit) if appended string length is too large to store in the buffer.
+ *   F_supported_not (with error bit) if this function is not available (due to not having libcap support compiled in).
+ *   F_failure (with error bit) on any other failure.
+ *
+ * @see cap_free()
+ * @see cap_to_text()
+ */
+#ifndef _di_f_capability_to_text_
+  extern f_return_status f_capability_to_text(const f_capability_t capability, f_string_dynamic_t *text);
+#endif // _di_f_capability_to_text_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _F_capability_h
diff --git a/level_0/f_capability/data/build/defines b/level_0/f_capability/data/build/defines
new file mode 100644 (file)
index 0000000..0d51e58
--- /dev/null
@@ -0,0 +1,3 @@
+# fss-0000
+_di_libcap_ Disable libcap support, allow for compiling and linking without libcap (-lcap).
+
diff --git a/level_0/f_capability/data/build/dependencies b/level_0/f_capability/data/build/dependencies
new file mode 100644 (file)
index 0000000..d798245
--- /dev/null
@@ -0,0 +1,6 @@
+# fss-0000
+
+f_type
+f_status
+f_memory
+f_string
diff --git a/level_0/f_capability/data/build/settings b/level_0/f_capability/data/build/settings
new file mode 100644 (file)
index 0000000..f1dccd4
--- /dev/null
@@ -0,0 +1,56 @@
+# fss-0001
+
+project_name f_capability
+
+version_major 0
+version_minor 5
+version_micro 2
+version_target major
+
+environment
+
+process_pre
+process_post
+
+modes individual
+modes_default individual
+
+build_compiler gcc
+build_indexer ar
+build_language c
+build_libraries -lc -lcap
+build_libraries-individual -lf_memory
+build_sources_library capability.c
+build_sources_program
+build_sources_headers capability.h capability-common.h
+build_sources_script
+build_sources_setting
+build_script yes
+build_shared yes
+build_static yes
+
+path_headers level_0
+path_headers_preserve no
+path_library_script script
+path_library_shared shared
+path_library_static static
+path_program_script script
+path_program_shared shared
+path_program_static static
+path_sources
+path_standard yes
+
+search_exclusive yes
+search_shared yes
+search_static yes
+
+#defines_all -D_di_libcap_
+defines_all
+defines_static
+defines_shared
+
+flags_all -z now -g -fdiagnostics-color=always
+flags_shared
+flags_static
+flags_library -fPIC
+flags_program -fPIE
index 7a9e7c68d7cbae5a1987a508875ef542004df7af..a43b0d66fe64c7a796fc324ad0df4bf646b3cbe4 100644 (file)
@@ -326,6 +326,8 @@ extern "C" {
       F_number_overflow,
       F_number_positive,
       F_number_positive_not,
+      F_number_too_large,
+      F_number_too_small,
       F_number_underflow,
       F_number_whole,
       F_number_whole_not,
index 5f42a4444984949d008f225e202a286117e42f2f..80d0aeafab45fe463114d05108b41076966bb477 100644 (file)
@@ -613,7 +613,11 @@ extern "C" {
       }
 
       if (string[i] == 0x30) {
-        j = i + 1;
+
+        // skip past all NULLs.
+        for (j = i + 1; j <= range.stop; ++j) {
+          if (string[j]) break;
+        } // for
 
         // Immediate next value must be either a number, 'x', 'X', 'd', 'D', 'o', 'O', 'b', or 'B'.
         if (j > range.stop) {
@@ -765,7 +769,11 @@ extern "C" {
       }
 
       if (string[i] == 0x30) {
-        j = i + 1;
+
+        // skip past all NULLs.
+        for (j = i + 1; j <= range.stop; ++j) {
+          if (string[j]) break;
+        } // for
 
         // Immediate next value must be either a number, 'x', 'X', 'd', 'D', 'o', 'O', 'b', or 'B'.
         if (j > range.stop) {
index 3a5610c0b9bd74919bef393df97efb48f8571706..e6be62a75b607bc3e1d9be0e5f05e5436dfc356f 100644 (file)
@@ -52,27 +52,6 @@ extern "C" {
 #endif // _di_fl_execute_parameter_t_
 
 /**
- * A structure representing an array of group ids.
- *
- * groups: a pointer to an array of groups.
- * size:   the length of the array of groups.
- */
-#ifndef _di_fl_execute_groups_t_
-  typedef struct {
-    gid_t *groups;
-    f_array_length_t size;
-  } fl_execute_groups_t;
-
-  #define fl_execute_groups_t_initialize { 0, 0 }
-
-  #define fl_macro_execute_groups_t_initialize(groups, size) { groups, size }
-
-  #define fl_execute_groups_t_clear(structure) \
-    structure.groups = 0; \
-    structure.size = 0;
-#endif // _di_fl_execute_groups_t_
-
-/**
  * A structure representing a scheduler and its parameters for execution.
  *
  * policy:    the scheduler policy.
@@ -98,41 +77,41 @@ extern "C" {
  *
  * There are likely many more identity and access related things that can be done but this focuses on a small core set of those.
  *
- * Note: Containers, or cgroups, exist here as a full file path in which the PID of a child process is to be written to.
- *       This may change as more is learned about using cgroups, but it is not known if there are any functions available like set_cgroup(..).
+ * Control Groups, or cgroups, exist here as a full file path in which the PID of a child process is to be written to.
+ * This may change as more is learned about using cgroups, but it is not known if there are any functions available like set_cgroup(..).
  *
  * nice:       the niceness value to assign the child process to, set to 0 to not use.
  * id_user:    the id of the user to assign the child process to, set to 0 to not use.
  * id_group:   the id of the group to assign the child process to, set to 0 to not use.
- * capability: all of the capabilities to assign the child process to, set to 0 to not use.
- * ids_group:  the ids of each supplemental group to assign the child process to, set to 0 to not use.
+ * capability: all of the capabilities to assign the child process to, set to 0 to not use (f_capability_t is a pointer).
+ * id_groups:  the ids of each supplemental group to assign the child process to, set to 0 to not use.
  * scheduler:  the scheduler to assign the child process to, set to 0 to not use.
- * containers: an array of cgroups (container groups) to assign the child PID to, set to 0 to not use.
+ * controls:   an array of cgroups (control groups) to assign the child PID to, set to 0 to not use.
  */
 #ifndef _di_fl_execute_as_t_
   typedef struct {
-    const int *nice;
-    const uid_t *id_user;
-    const gid_t *id_group;
-    //const cap_t *capability; // @todo
-
-    const fl_execute_groups_t *ids_group;
-    const fl_execute_scheduler_t *scheduler;
-    const f_string_dynamics_t *containers;
+    int *nice;
+    uid_t *id_user;
+    gid_t *id_group;
+    f_capability_t capability;
+
+    f_int32s_t *id_groups;
+    fl_execute_scheduler_t *scheduler;
+    f_string_dynamics_t *controls;
   } fl_execute_as_t;
 
-  #define fl_execute_as_t_initialize { 0, 0, 0, /*0,*/ fl_execute_groups_t_initialize, fl_execute_scheduler_t_initialize, f_string_dynamics_t_initialize }
+  #define fl_execute_as_t_initialize { 0, 0, 0, 0, 0, 0, 0 }
 
-  #define fl_macro_execute_as_t_initialize(nice, id_user, id_group, /*capability,*/ id_groups, scheduler, containers) { nice, id_user, id_group, /*capability,*/ id_groups, scheduler, containers }
+  #define fl_macro_execute_as_t_initialize(nice, id_user, id_group, capability, id_groups, scheduler, controls) { nice, id_user, id_group, capability, id_groups, scheduler, controls }
 
   #define fl_execute_as_t_clear(as) \
     as.nice = 0; \
     as.id_user = 0; \
     as.id_group = 0; \
-    /*as.capability = 0;*/ \
+    as.capability = 0; \
     as.id_groups = 0; \
     as.scheduler = 0; \
-    as.containers = 0;
+    as.controls = 0;
 #endif // _di_fl_execute_as_t_
 
 #ifdef __cplusplus
index cd5e08e4a8600773f902a4e0fdd62e3c6fd16d1d..ab3ba2d5fb7214f079aed122a80804331cf2ade2 100644 (file)
 // libc includes
 #include <grp.h>
 #include <sched.h>
-//#include <sys/capability.h> // @todo
 
 // fll-0 includes
 #include <level_0/type.h>
 #include <level_0/status.h>
 #include <level_0/execute.h>
 #include <level_0/signal.h>
+#include <level_0/type_array.h>
 
 // fll-1 execute includes
 #include <level_1/execute-common.h>
index 4f130804d83cb5bf412c3e349a4ac790b2b825ca..903c38c833c065f69dcff069c87eb4b052c103ab 100644 (file)
@@ -1 +1,2 @@
 # fss-0000
+_di_libcap_ Disable libcap support, allow for compiling and linking without libcap (-lcap).
index ded2e762fdc3043131463046ad44f9e1d221fbc7..7e334341da744fd587dc9530f09cd7bcf1dc0930 100644 (file)
@@ -3,5 +3,6 @@
 f_type
 f_status
 f_string
+f_capability
 f_signal
 f_execute
index 312de21c202f782d8df33bb35440c2196437268f..a13c57cd2781f9a5b481abda1e815a963810c127 100644 (file)
@@ -18,8 +18,8 @@ modes_default individual
 build_compiler gcc
 build_indexer ar
 build_language c
-build_libraries -lc
-build_libraries-individual -lf_memory -lf_signal
+build_libraries -lc -lcap
+build_libraries-individual -lf_capability -lf_memory -lf_signal
 build_sources_library
 build_sources_program
 build_sources_headers execute.h execute-common.h
@@ -44,6 +44,7 @@ search_exclusive yes
 search_shared yes
 search_static yes
 
+#defines_all -D_en_libcap_
 defines_all
 defines_static
 defines_shared
index 14bb0b3892207f8d8a42303cf0bb4a8c7cdeae7b..0b311ca15ebacf84f0551f8b49994f32fdf7f6ab 100644 (file)
@@ -737,6 +737,12 @@ extern "C" {
         case F_number_positive_not:
           *string = FL_status_string_number_positive_not;
           break;
+        case F_number_too_large:
+          *string = FL_status_string_number_too_large;
+          break;
+        case F_number_too_small:
+          *string = FL_status_string_number_too_small;
+          break;
         case F_number_underflow:
           *string = FL_status_string_number_underflow;
           break;
index 4fb4c29c50145a91434c31ffb73c4bd2f9a31b6c..f11acf6199ade8d2d2deb870975d60b257ae0724 100644 (file)
@@ -509,6 +509,8 @@ extern "C" {
     #define FL_status_string_number_overflow       "F_number_overflow"
     #define FL_status_string_number_positive       "F_number_positive"
     #define FL_status_string_number_positive_not   "F_number_positive_not"
+    #define FL_status_string_number_too_large      "F_number_too_large"
+    #define FL_status_string_number_too_small      "F_number_too_small"
     #define FL_status_string_number_underflow      "F_number_underflow"
     #define FL_status_string_number_whole          "F_number_whole"
     #define FL_status_string_number_whole_not      "F_number_whole_not"
@@ -525,6 +527,8 @@ extern "C" {
     #define FL_status_string_number_overflow_length       17
     #define FL_status_string_number_positive_length       17
     #define FL_status_string_number_positive_not_length   21
+    #define FL_status_string_number_too_large_length      18
+    #define FL_status_string_number_too_small_length      18
     #define FL_status_string_number_underflow_length      18
     #define FL_status_string_number_whole_length          14
     #define FL_status_string_number_whole_not_length      18
index ce34a3d6a3e973178483562f9767cbf742622b79..2ba0dfbcee80d84710f42631501eedb72b4ad523 100644 (file)
@@ -6,6 +6,9 @@
  * Licenses: lgplv2.1
  *
  * Provides program execution operations similar to system().
+ *
+ * Some functions support capabilities, which are POSIX compliant as of POSIX 1003.1e (as a draft).
+ * Because it is only in POSIX as a draft, they are available via libcap instead of libc.
  */
 #ifndef _FLL_execute_h
 #define _FLL_execute_h
@@ -25,6 +28,7 @@
 #include <level_0/memory.h>
 #include <level_0/string.h>
 #include <level_0/utf.h>
+#include <level_0/capability.h>
 #include <level_0/environment.h>
 #include <level_0/execute.h>
 #include <level_0/file.h>
@@ -425,6 +429,7 @@ extern "C" {
  *   F_schedule (with error bit) on failure to set scheduler in the child (only the child process returns this).
  *   F_user (with error bit) on failure to set UID in the child (only the child process returns this).
  *
+ *   Errors (with error bit) from: f_capability_process_set().
  *   Errors (with error bit) from: f_environment_get().
  *   Errors (with error bit) from: f_file_exists().
  *   Errors (with error bit) from: f_macro_string_dynamics_t_delete().
@@ -434,7 +439,6 @@ extern "C" {
  *   Errors (with error bit) from: fl_string_dynamic_delete().
  *   Errors (with error bit) from: fl_string_dynamic_terminate().
  *
- * @see cap_set_proc()
  * @see close()
  * @see clearenv()
  * @see dup2()
@@ -453,6 +457,7 @@ extern "C" {
  * @see strnlen()
  * @see waitpid()
  *
+ * @see f_capability_process_set()
  * @see f_environment_get()
  * @see f_file_exists()
  * @see f_signal_set_handle()
index c3f81540c780f45b8f44cd388874bd90e5dc08bb..b4241594e4799c435f039b35af0a469d80ced719 100644 (file)
@@ -149,9 +149,10 @@ extern "C" {
       }
     }
 
-    /* @todo library dependencies, if this is not in libc, then this may not be supported. more investigation is needed.
     if (as.capability) {
-      if (cap_set_proc(*as.capability) == -1) {
+      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) {
@@ -161,10 +162,9 @@ extern "C" {
         return F_status_set_error(F_capability);
       }
     }
-    */
 
-    if (as.ids_group) {
-      if (setgroups(as.ids_group->size, as.ids_group->groups) == -1) {
+    if (as.id_groups) {
+      if (setgroups(as.id_groups->used, as.id_groups->array) == -1) {
         *result = -1;
 
         if (parameter && parameter->option & fl_execute_parameter_option_exit) {
index 6abd480c579b2a19351372e7ef30433127db028f..3e9a0486d7dc92a837451dd16bd3f0a528598c7d 100644 (file)
@@ -127,7 +127,6 @@ extern "C" {
  *   F_schedule (with error bit) on failure to set scheduler.
  *   F_user (with error bit) on failure to set UID.
  *
- * @see cap_set_proc()
  * @see exit()
  * @see getpid()
  * @see nice()
@@ -136,6 +135,7 @@ extern "C" {
  * @see setgroups()
  * @see setuid()
  *
+ * @see f_capability_process_set()
  * @see fll_execute_program()
  */
 #if !defined(_di_fll_execute_program_)
index c6653172ef1e71eb1aff738b1cbad4300feeacd6..903c38c833c065f69dcff069c87eb4b052c103ab 100644 (file)
@@ -1,2 +1,2 @@
 # fss-0000
-
+_di_libcap_ Disable libcap support, allow for compiling and linking without libcap (-lcap).
index 44e3cdb68873d10e2d80ff813997599eb3fee8b5..9f340366dc0d9d9552aa07710aa96bb0953c5d46 100644 (file)
@@ -4,6 +4,7 @@ f_type
 f_status
 f_memory
 f_string
+f_capability
 f_environment
 f_execute
 f_file
index aec09665b5af16819d4558118869489a03068e96..a789937bcc34e9879e768b15c95686cc1b514460 100644 (file)
@@ -18,8 +18,8 @@ modes_default individual
 build_compiler gcc
 build_indexer ar
 build_language c
-build_libraries -lc
-build_libraries-individual -lfl_environment -lfl_string -lf_environment -lf_file -lf_memory -lf_path -lf_signal -lf_utf
+build_libraries -lc -lcap
+build_libraries-individual -lfl_environment -lfl_string -lf_capability -lf_environment -lf_file -lf_memory -lf_path -lf_signal -lf_utf
 build_sources_library execute.c private-execute.c
 build_sources_program
 build_sources_headers execute.h
index 16aa35bed3206801f4501df2309644450cca6948..6d749f566e3b1887d6fe68c3a299ce8f1aaa2626 100644 (file)
@@ -1219,6 +1219,16 @@ extern "C" {
         return F_none;
       }
 
+      if (fl_string_compare(string, FL_status_string_number_too_large, length, FL_status_string_number_too_large_length) == F_equal_to) {
+        *code = F_number_too_large;
+        return F_none;
+      }
+
+      if (fl_string_compare(string, FL_status_string_number_too_small, length, FL_status_string_number_too_small_length) == F_equal_to) {
+        *code = F_number_too_small;
+        return F_none;
+      }
+
       if (fl_string_compare(string, FL_status_string_number_underflow, length, FL_status_string_number_underflow_length) == F_equal_to) {
         *code = F_number_underflow;
         return F_none;
index fc659835c8f4007bcd36df283a1e682cc5b69a9f..88c1ab7d8cbf7e9d6b0e3881c5cce269c99dc581 100644 (file)
@@ -26,6 +26,7 @@ extern "C" {
 
     fprintf(output.stream, "%c", f_string_eol_s[0]);
 
+    fll_program_print_help_option(output, context, controller_short_control, controller_long_control, f_console_symbol_short_enable, f_console_symbol_long_enable, "      Specify a custom control group file path, such as '" controller_path_control "'.");
     fll_program_print_help_option(output, context, controller_short_daemon, controller_long_daemon, f_console_symbol_short_enable, f_console_symbol_long_enable, "       Run in daemon only mode (do not process the entry).");
     fll_program_print_help_option(output, context, controller_short_interruptable, controller_long_interruptable, f_console_symbol_short_enable, f_console_symbol_long_enable, "Designate that this program can be interrupted.");
     fll_program_print_help_option(output, context, controller_short_pid, controller_long_pid, f_console_symbol_short_enable, f_console_symbol_long_enable, "          Specify a custom pid file path, such as '" controller_path_pid controller_string_default controller_path_suffix "'.");
@@ -252,6 +253,49 @@ extern "C" {
       }
     }
 
+    if (data->parameters[controller_parameter_control].result == f_console_result_found) {
+      if (data->error.verbosity != f_console_verbosity_quiet) {
+        fprintf(data->error.to.stream, "%c", f_string_eol_s[0]);
+        fprintf(data->error.to.stream, "%s%sThe parameter '", data->error.context.before->string, data->error.prefix ? data->error.prefix : f_string_empty_s);
+        fprintf(data->error.to.stream, "%s%s%s%s%s", data->error.context.after->string, data->error.notable.before->string, f_console_symbol_long_enable, controller_long_control, data->error.notable.after->string);
+        fprintf(data->error.to.stream, "%s' was specified, but no value was given.%s%c", data->error.context.before->string, data->error.context.after->string, f_string_eol_s[0]);
+      }
+
+      status = F_status_set_error(F_parameter);
+    }
+    else if (data->parameters[controller_parameter_control].locations.used) {
+      const f_array_length_t location = data->parameters[controller_parameter_control].values.array[data->parameters[controller_parameter_control].values.used - 1];
+
+      if (strnlen(arguments.argv[location], f_console_length_size)) {
+        status = fll_path_canonical(arguments.argv[location], &setting.path_control);
+
+        if (F_status_is_error(status)) {
+          if (data->error.verbosity != f_console_verbosity_quiet) {
+            fll_error_print(data->error, F_status_set_fine(status), "fll_path_canonical", F_true);
+          }
+        }
+      }
+      else {
+        if (data->warning.verbosity == f_console_verbosity_debug) {
+          fprintf(data->warning.to.stream, "%c", f_string_eol_s[0]);
+          fprintf(data->warning.to.stream, "%s%sThe parameter '", data->warning.context.before->string, data->warning.prefix ? data->warning.prefix : f_string_empty_s);
+          fprintf(data->warning.to.stream, "%s%s%s%s%s", data->warning.context.after->string, data->warning.notable.before->string, f_console_symbol_long_enable, controller_long_control, data->warning.notable.after->string);
+          fprintf(data->warning.to.stream, "%s' must be a file directory path but instead is an empty string, falling back to the default.%s%c", data->warning.context.before->string, data->warning.context.after->string, f_string_eol_s[0]);
+        }
+      }
+    }
+
+    // a control file path is required.
+    if (!setting.path_control.used) {
+      status = fl_string_append(controller_path_control, controller_path_control_length, &setting.path_control);
+
+      if (F_status_is_error(status)) {
+        if (data->error.verbosity != f_console_verbosity_quiet) {
+          fll_error_print(data->error, F_status_set_fine(status), "fl_string_append", F_true);
+        }
+      }
+    }
+
     if (data->parameters[controller_parameter_daemon].result == f_console_result_found) {
 
       if (data->parameters[controller_parameter_validate].result == f_console_result_found) {
index 632a465d099af449caf4d04d1cdaaec91ce0373f..a59dafb5370dc4e65e441adf0d618d9e554de1a0 100644 (file)
@@ -30,6 +30,8 @@
 #include <level_0/memory.h>
 #include <level_0/string.h>
 #include <level_0/utf.h>
+#include <level_0/account.h>
+#include <level_0/capability.h>
 #include <level_0/color.h>
 #include <level_0/console.h>
 #include <level_0/directory.h>
@@ -83,14 +85,17 @@ extern "C" {
 
   #define controller_default_program_script "bash"
 
+  #define controller_path_control  "/sys/fs/cgroup/unified"
   #define controller_path_pid      "/var/run/controller/controller-"
   #define controller_path_settings "/etc/controller"
   #define controller_path_suffix   ".pid"
 
+  #define controller_path_control_length  22
   #define controller_path_pid_length      31
   #define controller_path_settings_length 15
   #define controller_path_suffix_length   4
 
+  #define controller_short_control       "c"
   #define controller_short_daemon        "d"
   #define controller_short_interruptable "i"
   #define controller_short_pid           "p"
@@ -98,6 +103,7 @@ extern "C" {
   #define controller_short_test          "t"
   #define controller_short_validate      "v"
 
+  #define controller_long_control       "control"
   #define controller_long_daemon        "daemon"
   #define controller_long_interruptable "interruptable"
   #define controller_long_pid           "pid"
@@ -116,6 +122,7 @@ extern "C" {
     controller_parameter_verbosity_debug,
     controller_parameter_version,
 
+    controller_parameter_control,
     controller_parameter_daemon,
     controller_parameter_interruptable,
     controller_parameter_pid,
@@ -135,6 +142,7 @@ extern "C" {
       f_console_parameter_t_initialize(f_console_standard_short_verbose, f_console_standard_long_verbose, 0, 0, f_console_type_inverse), \
       f_console_parameter_t_initialize(f_console_standard_short_debug, f_console_standard_long_debug, 0, 0, f_console_type_inverse), \
       f_console_parameter_t_initialize(f_console_standard_short_version, f_console_standard_long_version, 0, 0, f_console_type_inverse), \
+      f_console_parameter_t_initialize(controller_short_control, controller_long_control, 0, 1, f_console_type_normal), \
       f_console_parameter_t_initialize(controller_short_daemon, controller_long_daemon, 0, 0, f_console_type_normal), \
       f_console_parameter_t_initialize(controller_short_interruptable, controller_long_interruptable, 0, 0, f_console_type_normal), \
       f_console_parameter_t_initialize(controller_short_pid, controller_long_pid, 0, 1, f_console_type_normal), \
@@ -143,7 +151,7 @@ extern "C" {
       f_console_parameter_t_initialize(controller_short_validate, controller_long_validate, 0, 0, f_console_type_normal), \
     }
 
-  #define controller_total_parameters 15
+  #define controller_total_parameters 16
 #endif // _di_controller_defines_
 
 #ifndef _di_controller_data_t_
index dbe8fdc8743e47d5d3c937e4f8d00fae4a0c182c..ad9aba96b62ea122532293199024752fc0d48e9e 100644 (file)
@@ -17,10 +17,11 @@ extern "C" {
   #define controller_string_actions       "actions"
   #define controller_string_asynchronous  "asynchronous"
   #define controller_string_bash          "bash"
+  #define controller_string_capability    "capability"
   #define controller_string_create        "create"
   #define controller_string_command       "command"
   #define controller_string_consider      "consider"
-  #define controller_string_control_group "control_group"
+  #define controller_string_control       "control"
   #define controller_string_default       "default"
   #define controller_string_define        "define"
   #define controller_string_entry         "entry"
@@ -29,6 +30,7 @@ extern "C" {
   #define controller_string_fail          "fail"
   #define controller_string_failsafe      "failsafe"
   #define controller_string_group         "group"
+  #define controller_string_groups        "groups"
   #define controller_string_how           "how"
   #define controller_string_item          "item"
   #define controller_string_kill          "kill"
@@ -36,6 +38,7 @@ extern "C" {
   #define controller_string_method        "method"
   #define controller_string_name          "name"
   #define controller_string_need          "need"
+  #define controller_string_nice          "nice"
   #define controller_string_no            "no"
   #define controller_string_optional      "optional"
   #define controller_string_parameter     "parameter"
@@ -49,6 +52,7 @@ extern "C" {
   #define controller_string_restart       "restart"
   #define controller_string_rule          "rule"
   #define controller_string_rules         "rules"
+  #define controller_string_scheduler     "scheduler"
   #define controller_string_script        "script"
   #define controller_string_service       "service"
   #define controller_string_setting       "setting"
@@ -69,10 +73,11 @@ extern "C" {
   #define controller_string_actions_length       7
   #define controller_string_asynchronous_length  12
   #define controller_string_bash_length          4
+  #define controller_string_capability_length    10
   #define controller_string_create_length        6
   #define controller_string_command_length       7
   #define controller_string_consider_length      8
-  #define controller_string_control_group_length 13
+  #define controller_string_control_length       7
   #define controller_string_define_length        6
   #define controller_string_default_length       7
   #define controller_string_entry_length         5
@@ -88,6 +93,7 @@ extern "C" {
   #define controller_string_method_length        6
   #define controller_string_name_length          4
   #define controller_string_need_length          4
+  #define controller_string_nice_length          4
   #define controller_string_no_length            2
   #define controller_string_optional_length      8
   #define controller_string_parameter_length     9
@@ -101,6 +107,7 @@ extern "C" {
   #define controller_string_restart_length       7
   #define controller_string_rule_length          4
   #define controller_string_rules_length         5
+  #define controller_string_scheduler_length     9
   #define controller_string_script_length        6
   #define controller_string_service_length       7
   #define controller_string_setting_length       7
@@ -242,14 +249,19 @@ extern "C" {
 
 #ifndef _di_controller_rule_t_
   enum {
-    controller_rule_setting_type_control_group = 1,
+    controller_rule_setting_type_capability = 1,
+    controller_rule_setting_type_control,
     controller_rule_setting_type_define,
     controller_rule_setting_type_environment,
+    controller_rule_setting_type_group,
     controller_rule_setting_type_name,
     controller_rule_setting_type_need,
+    controller_rule_setting_type_nice,
     controller_rule_setting_type_parameter,
     controller_rule_setting_type_path,
+    controller_rule_setting_type_scheduler,
     controller_rule_setting_type_script,
+    controller_rule_setting_type_user,
     controller_rule_setting_type_want,
     controller_rule_setting_type_wish,
   };
@@ -259,6 +271,11 @@ extern "C" {
   #define controller_rule_option_simulate     0x4
   #define controller_rule_option_wait         0x8
 
+  // bitwise codes representing properties on controller_rule_t that have been found in the rule file.
+  #define controller_rule_has_group 0x1
+  #define controller_rule_has_nice  0x2
+  #define controller_rule_has_user  0x4
+
   typedef struct {
     f_status_t status;
     f_number_signed_t process; // @todo: for background/threaded support (ideally should hold the process id, but remove if this ends up not being the strategy) (this can also be used by the parent/main process to check to see if the child no longer a child of this process).
@@ -267,12 +284,18 @@ extern "C" {
     f_number_unsigned_t timeout_start;
     f_number_unsigned_t timeout_stop;
 
+    uint8_t has;
+    int nice;
+    uid_t user;
+    gid_t group;
+
     f_time_spec_t timestamp;
 
     f_string_dynamic_t id;
     f_string_dynamic_t name;
-    f_string_dynamic_t control_group;
+    f_string_dynamic_t control;
     f_string_dynamic_t path;
+    f_string_dynamic_t scheduler;
     f_string_dynamic_t script;
 
     f_string_maps_t define;
@@ -283,6 +306,9 @@ extern "C" {
     f_string_dynamics_t want;
     f_string_dynamics_t wish;
 
+    f_capability_t capability;
+    f_int32s_t groups;
+
     controller_rule_items_t items;
   } controller_rule_t;
 
@@ -293,26 +319,34 @@ extern "C" {
       0, \
       0, \
       0, \
+      0, \
+      0, \
+      0, \
+      0, \
       f_time_spec_t_initialize, \
       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, \
+      f_string_dynamic_t_initialize, \
       f_string_maps_t_initialize, \
       f_string_maps_t_initialize, \
       f_string_dynamics_t_initialize, \
       f_string_dynamics_t_initialize, \
       f_string_dynamics_t_initialize, \
       f_string_dynamics_t_initialize, \
+      f_capability_t_initialize, \
+      f_int32s_t_initialize, \
       controller_rule_items_initialize, \
     }
 
   #define controller_macro_rule_t_delete_simple(rule) \
     fl_string_dynamic_delete(&rule.id); \
     fl_string_dynamic_delete(&rule.name); \
-    fl_string_dynamic_delete(&rule.control_group); \
+    fl_string_dynamic_delete(&rule.control); \
     fl_string_dynamic_delete(&rule.path); \
+    fl_string_dynamic_delete(&rule.scheduler); \
     fl_string_dynamic_delete(&rule.script); \
     f_macro_string_maps_t_delete_simple(rule.define) \
     f_macro_string_maps_t_delete_simple(rule.parameter) \
@@ -320,6 +354,8 @@ extern "C" {
     fl_string_dynamics_delete(&rule.need); \
     fl_string_dynamics_delete(&rule.want); \
     fl_string_dynamics_delete(&rule.wish); \
+    f_capability_delete(&rule.capability); \
+    fl_type_int32s_delete(&rule.groups); \
     controller_macro_rule_items_t_delete_simple(rule.items)
 #endif // _di_controller_rule_t_
 
@@ -500,6 +536,7 @@ extern "C" {
     bool failsafe_enabled;
     f_array_length_t failsafe_rule_id;
 
+    f_string_dynamic_t path_control;
     f_string_dynamic_t path_pid;
     f_string_dynamic_t path_setting;
 
@@ -519,11 +556,13 @@ extern "C" {
       0, \
       f_string_dynamic_t_initialize, \
       f_string_dynamic_t_initialize, \
+      f_string_dynamic_t_initialize, \
       controller_entry_t_initialize, \
       controller_rules_t_initialize, \
     }
 
   #define controller_macro_setting_t_delete_simple(setting) \
+    fl_string_dynamic_delete(&setting.path_control); \
     fl_string_dynamic_delete(&setting.path_pid); \
     fl_string_dynamic_delete(&setting.path_setting); \
     controller_macro_entry_t_delete_simple(setting.entry) \
@@ -553,6 +592,7 @@ extern "C" {
 
     f_string_dynamic_t buffer_file;
     f_string_dynamic_t buffer_item;
+    f_string_dynamic_t buffer_other;
     f_string_dynamic_t buffer_path;
 
     f_string_dynamic_t name_action;
@@ -581,6 +621,7 @@ extern "C" {
       f_string_dynamic_t_initialize, \
       f_string_dynamic_t_initialize, \
       f_string_dynamic_t_initialize, \
+      f_string_dynamic_t_initialize, \
     }
 
   #define controller_macro_cache_t_delete_simple(cache) \
@@ -595,6 +636,7 @@ extern "C" {
     f_macro_fss_objects_t_delete_simple(cache.object_items) \
     fl_string_dynamic_delete(&cache.buffer_file); \
     fl_string_dynamic_delete(&cache.buffer_item); \
+    fl_string_dynamic_delete(&cache.buffer_other); \
     fl_string_dynamic_delete(&cache.buffer_path); \
     fl_string_dynamic_delete(&cache.name_action); \
     fl_string_dynamic_delete(&cache.name_file); \
index 198211f65a8624e5e6a74f893f61b74585ce08fe..6ba50bec21f2cc2284f37c41affbf03cd94b6706 100644 (file)
@@ -218,6 +218,90 @@ extern "C" {
   }
 #endif // _di_controller_file_pid_delete_
 
+#ifndef _di_controller_get_id_user_
+  f_return_status controller_get_id_user(const f_string_static_t buffer, const f_string_range_t range, controller_cache_t *cache, uid_t *id) {
+    f_number_unsigned_t number = 0;
+
+    // @todo fix argument ordering in fl_conversion_string_to_number_unsigned().
+    f_status_t status = fl_conversion_string_to_number_unsigned(buffer.string, &number, range);
+
+    if (F_status_is_error(status)) {
+      status = F_status_set_fine(status);
+
+      if (status == F_number) {
+        cache->buffer_other.used = 0;
+
+        status = fl_string_dynamic_partial_append_nulless(buffer, range, &cache->buffer_other);
+
+        if (F_status_is_error(status)) {
+          return F_status_set_error(status);
+        }
+
+        status = f_account_id_user_by_name(cache->buffer_other.string, id);
+
+        if (F_status_is_error(status)) {
+          return F_status_set_error(status);
+        }
+        else if (status == F_exist_not) {
+          return F_status_set_error(F_exist_not);
+        }
+
+        return F_none;
+      }
+
+      return F_status_set_error(status);
+    }
+    else if (number > f_type_size_32_unsigned) {
+      return F_status_set_error(F_number_too_large);
+    }
+
+    *id = (uid_t) number;
+    return status;
+  }
+#endif // _di_controller_get_id_user_
+
+#ifndef _di_controller_get_id_group_
+  f_return_status controller_get_id_group(const f_string_static_t buffer, const f_string_range_t range, controller_cache_t *cache, gid_t *id) {
+    f_number_unsigned_t number = 0;
+
+    // @todo fix argument ordering in fl_conversion_string_to_number_unsigned().
+    f_status_t status = fl_conversion_string_to_number_unsigned(buffer.string, &number, range);
+
+    if (F_status_is_error(status)) {
+      status = F_status_set_fine(status);
+
+      if (status == F_number) {
+        cache->buffer_other.used = 0;
+
+        status = fl_string_dynamic_partial_append_nulless(buffer, range, &cache->buffer_other);
+
+        if (F_status_is_error(status)) {
+          return F_status_set_error(status);
+        }
+
+        status = f_account_id_group_by_name(cache->buffer_other.string, id);
+
+        if (F_status_is_error(status)) {
+          return F_status_set_error(status);
+        }
+        else if (status == F_exist_not) {
+          return F_status_set_error(F_exist_not);
+        }
+
+        return F_none;
+      }
+
+      return F_status_set_error(status);
+    }
+    else if (number > f_type_size_32_unsigned) {
+      return F_status_set_error(F_number_too_large);
+    }
+
+    *id = (gid_t) number;
+    return status;
+  }
+#endif // _di_controller_get_id_group_
+
 #ifndef _di_controller_perform_ready_
   f_return_status controller_perform_ready(const controller_data_t data, controller_setting_t *setting, controller_cache_t *cache) {
     f_status_t status = F_none;
index d9c0d786115b169a85dd545acbc529894d4c336c..70f4402bd7cd0bca2398f685fc1a9d0af8475ad1 100644 (file)
@@ -159,6 +159,60 @@ extern "C" {
 #endif // _di_controller_file_pid_delete_
 
 /**
+ * Convert the string from a string representation of an ID or a user name into the numeric representation of that ID or user name.
+ *
+ * @param buffer
+ *   A string containing user name or ID.
+ * @param range
+ *   The range within the buffer specifically containing the name or ID.
+ * @param cache
+ *   The cache.
+ * @param id
+ *   The determined user ID.
+ *
+ * @return
+ *   F_none on success.
+ *   F_exist_not (with error bit) if failed to match the name to an ID.
+ *   F_number_too_large (with error bit) if the given ID is too large.
+ *
+ *   Errors (with error bit) from: f_account_id_user_by_name().
+ *   Errors (with error bit) from: fl_conversion_string_to_number_unsigned().
+ *
+ * @see f_account_id_user_by_name()
+ * @see fl_conversion_string_to_number_unsigned()
+ */
+#ifndef _di_controller_get_id_user_
+  f_return_status controller_get_id_user(const f_string_static_t buffer, const f_string_range_t range, controller_cache_t *cache, uid_t *id) f_gcc_attribute_visibility_internal;
+#endif // _di_controller_get_id_user_
+
+/**
+ * Convert the string from a string representation of an ID or a group name into the numeric representation of that ID or group name.
+ *
+ * @param buffer
+ *   A string containing group name or ID.
+ * @param range
+ *   The range within the buffer specifically containing the name or ID.
+ * @param cache
+ *   The cache.
+ * @param id
+ *   The determined group ID.
+ *
+ * @return
+ *   F_none on success.
+ *   F_exist_not (with error bit) if failed to match the name to an ID.
+ *   F_number_too_large (with error bit) if the given ID is too large.
+ *
+ *   Errors (with error bit) from: f_account_id_group_by_name().
+ *   Errors (with error bit) from: fl_conversion_string_to_number_unsigned().
+ *
+ * @see f_account_id_group_by_name()
+ * @see fl_conversion_string_to_number_unsigned()
+ */
+#ifndef _di_controller_get_id_group_
+  f_return_status controller_get_id_group(const f_string_static_t buffer, const f_string_range_t range, controller_cache_t *cache, gid_t *id) f_gcc_attribute_visibility_internal;
+#endif // _di_controller_get_id_group_
+
+/**
  * Perform all activities requiring the state to be "ready".
  *
  * This prints messages on errors.
index 23ac512f539bcd7928def264b3cf0efb915b49f2..83198caa0d8113fc5c7e7c2173468541ea29ade3 100644 (file)
@@ -458,6 +458,35 @@ extern "C" {
 
     const f_string_dynamics_t arguments_none = f_string_dynamics_t_initialize;
     fl_execute_parameter_t parameter = fl_macro_execute_parameter_t_initialize(0, &environment, &signals, 0);
+    fl_execute_as_t as = fl_execute_as_t_initialize;
+
+    if (rule->has & controller_rule_has_nice) {
+      as.nice = &rule->nice;
+    }
+
+    if (rule->has & controller_rule_has_user) {
+      as.id_user = &rule->user;
+    }
+
+    if (rule->has & controller_rule_has_group) {
+      as.id_group = &rule->group;
+
+      if (rule->groups.used) {
+        as.id_groups = &rule->groups;
+      }
+    }
+
+    if (rule->capability) {
+      as.capability = rule->capability;
+    }
+
+    if (rule->scheduler.used) {
+      // @todo: as.scheduler =
+    }
+
+    if (rule->control.used) {
+      // @todo: as.controls =
+    }
 
     status = fll_environment_load_names(rule->environment, &environment);
 
@@ -487,7 +516,11 @@ extern "C" {
             parameter.option |= fl_execute_parameter_option_path;
           }
 
-          status = controller_rule_execute_foreground(item->type, *action, 0, action->parameters, 0, &parameter, data);
+          status = controller_rule_execute_foreground(item->type, *action, 0, action->parameters, 0, &parameter, &as, data);
+
+          if (status == F_child) {
+            break;
+          }
 
           if (F_status_is_error(status)) {
             action->status = F_status_set_error(F_failure);
@@ -503,7 +536,11 @@ extern "C" {
             parameter.option |= fl_execute_parameter_option_path;
           }
 
-          status = controller_rule_execute_foreground(item->type, *action, rule->script.used ? rule->script.string : controller_default_program_script, arguments_none, 0, &parameter, data);
+          status = controller_rule_execute_foreground(item->type, *action, rule->script.used ? rule->script.string : controller_default_program_script, arguments_none, 0, &parameter, &as, data);
+
+          if (status == F_child) {
+            break;
+          }
 
           if (F_status_is_error(status)) {
             action->status = F_status_set_error(F_failure);
@@ -518,7 +555,7 @@ extern "C" {
             parameter.option |= fl_execute_parameter_option_path;
           }
 
-          status = controller_rule_execute_pid_with(item->type, *action, 0, action->parameters, 0, &parameter, data);
+          status = controller_rule_execute_pid_with(item->type, *action, 0, action->parameters, 0, &parameter, &as, data);
 
           if (F_status_is_error(status)) {
             action->status = F_status_set_error(F_failure);
@@ -553,6 +590,10 @@ extern "C" {
 
     fl_string_maps_delete(&environment);
 
+    if (status == F_child) {
+      return status;
+    }
+
     if (F_status_is_error(status) || success == F_false) {
       rule->status = F_status_set_error(F_failure);
     }
@@ -568,7 +609,7 @@ extern "C" {
 #endif // _di_controller_rule_execute_
 
 #ifndef _di_controller_rule_execute_pid_with_
-  f_return_status controller_rule_execute_pid_with(const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, fl_execute_parameter_t * const parameter, controller_data_t *data) {
+  f_return_status controller_rule_execute_pid_with(const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, fl_execute_parameter_t * const parameter, fl_execute_as_t * const as, controller_data_t *data) {
     int result = 0;
 
     // @todo check to see if pid file exists.
@@ -577,7 +618,18 @@ extern "C" {
     //       in which case fll_execute_program() is called.
     //       otherwise this needs to call an asynchronous execute process.
     //       until then, this controller_rule_execute_pid_with() function is not correct and only represents a process that forks to the background.
-    f_status_t status = fll_execute_program(program, arguments, parameter, 0, &result);
+    f_status_t status = fll_execute_program(program, arguments, parameter, as, &result);
+
+    if (F_status_is_error(status)) {
+      status = F_status_set_fine(status);
+
+      if (status == F_child || status == F_capability || status == F_group || status == F_nice || status == F_schedule || status == F_user) {
+        status = F_child;
+      }
+      else {
+        status = F_status_set_error(status);
+      }
+    }
 
     if (status == F_child) {
       data->child = result;
@@ -591,7 +643,7 @@ extern "C" {
 
     if (F_status_is_error(status)) {
       if (F_status_set_fine(status) == F_failure) {
-        controller_rule_error_print_execute(data->error, type == controller_rule_item_type_script, program, result);
+        controller_rule_error_print_execute(data->error, type == controller_rule_item_type_script, program ? program : arguments.used ? arguments.array[0].string : f_string_empty_s, result);
       }
       else if (F_status_set_fine(status) == F_file_found_not) {
         controller_rule_error_print_execute_not_found(data->error, F_false, program);
@@ -614,10 +666,21 @@ extern "C" {
 #endif // _di_controller_rule_execute_pid_with_
 
 #ifndef _di_controller_rule_execute_foreground_
-  f_return_status controller_rule_execute_foreground(const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, fl_execute_parameter_t * const parameter, controller_data_t *data) {
+  f_return_status controller_rule_execute_foreground(const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, fl_execute_parameter_t * const parameter, fl_execute_as_t * const as, controller_data_t *data) {
     int result = 0;
 
-    f_status_t status = fll_execute_program(program, arguments, parameter, 0, &result);
+    f_status_t status = fll_execute_program(program, arguments, parameter, as, &result);
+
+    if (F_status_is_error(status)) {
+      status = F_status_set_fine(status);
+
+      if (status == F_child || status == F_capability || status == F_group || status == F_nice || status == F_schedule || status == F_user) {
+        status = F_child;
+      }
+      else {
+        status = F_status_set_error(status);
+      }
+    }
 
     if (status == F_child) {
       data->child = result;
@@ -631,7 +694,7 @@ extern "C" {
 
     if (F_status_is_error(status)) {
       if (F_status_set_fine(status) == F_failure) {
-        controller_rule_error_print_execute(data->error, type == controller_rule_item_type_script, program, result);
+        controller_rule_error_print_execute(data->error, type == controller_rule_item_type_script, program ? program : arguments.used ? arguments.array[0].string : f_string_empty_s, result);
       }
       else if (F_status_set_fine(status) == F_file_found_not) {
         controller_rule_error_print_execute_not_found(data->error, F_false, program);
@@ -1078,7 +1141,7 @@ extern "C" {
     controller_rule_t *rule = &setting->rules.array[index];
 
     if ((options & controller_rule_option_simulate) && data->parameters[controller_parameter_validate].result == f_console_result_found) {
-      controller_rule_simulate(*data, *cache, index, controller_rule_action_type_start, options, setting);
+      controller_rule_simulate(*data, index, controller_rule_action_type_start, options, cache, setting);
     }
 
     {
@@ -1285,20 +1348,42 @@ extern "C" {
     bool for_item = F_true;
 
     rule->status = F_known_not;
+    rule->process = 0;
+
+    // @todo: timeouts may be passed from entry, consider to or not to initialize in a more consistent manner.
+    //rule->timeout_kill = 2;
+    //rule->timeout_start = 2;
+    //rule->timeout_stop = 2;
+
+    rule->has = 0;
+    rule->group = 0;
+    rule->user = 0;
+    rule->nice = 0;
 
     f_macro_time_spec_t_clear(rule->timestamp);
 
     rule->id.used = 0;
     rule->name.used = 0;
+    rule->control.used = 0;
+    rule->path.used = 0;
+    rule->scheduler.used = 0;
+    rule->script.used = 0;
 
     rule->define.used = 0;
     rule->parameter.used = 0;
 
+    if (rule->capability) {
+      f_capability_delete(&rule->capability);
+    }
+
+    rule->capability = 0;
     rule->environment.used = 0;
     rule->need.used = 0;
     rule->want.used = 0;
     rule->wish.used = 0;
 
+    rule->groups.used = 0;
+
     rule->items.used = 0;
 
     cache->line_item = 0;
@@ -1465,7 +1550,7 @@ extern "C" {
           else {
             for_item = F_false;
 
-            status = controller_rule_setting_read(data, cache, rule);
+            status = controller_rule_setting_read(data, setting, cache, rule);
 
             if (F_status_is_error(status)) {
               if (F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_memory_allocation || F_status_set_fine(status) == F_memory_reallocation) {
@@ -1490,7 +1575,7 @@ extern "C" {
 #endif // _di_controller_rule_read_
 
 #ifndef _di_controller_rule_setting_read_
-  f_return_status controller_rule_setting_read(const controller_data_t data, controller_cache_t *cache, controller_rule_t *rule) {
+  f_return_status controller_rule_setting_read(const controller_data_t data, const controller_setting_t setting, controller_cache_t *cache, controller_rule_t *rule) {
     f_status_t status = F_none;
     f_status_t status_return = F_none;
 
@@ -1545,8 +1630,11 @@ extern "C" {
         continue;
       }
 
-      if (fl_string_dynamic_compare_string(controller_string_control_group, cache->name_item, controller_string_control_group_length) == F_equal_to) {
-        type = controller_rule_setting_type_control_group;
+      if (fl_string_dynamic_compare_string(controller_string_capability, cache->name_item, controller_string_capability_length) == F_equal_to) {
+        type = controller_rule_setting_type_capability;
+      }
+      else if (fl_string_dynamic_compare_string(controller_string_control, cache->name_item, controller_string_control_length) == F_equal_to) {
+        type = controller_rule_setting_type_control;
       }
       else if (fl_string_dynamic_compare_string(controller_string_define, cache->name_item, controller_string_define_length) == F_equal_to) {
         type = controller_rule_setting_type_define;
@@ -1554,21 +1642,33 @@ extern "C" {
       else if (fl_string_dynamic_compare_string(controller_string_environment, cache->name_item, controller_string_environment_length) == F_equal_to) {
         type = controller_rule_setting_type_environment;
       }
+      else if (fl_string_dynamic_compare_string(controller_string_group, cache->name_item, controller_string_group_length) == F_equal_to) {
+        type = controller_rule_setting_type_group;
+      }
       else if (fl_string_dynamic_compare_string(controller_string_name, cache->name_item, controller_string_name_length) == F_equal_to) {
         type = controller_rule_setting_type_name;
       }
       else if (fl_string_dynamic_compare_string(controller_string_need, cache->name_item, controller_string_need_length) == F_equal_to) {
         type = controller_rule_setting_type_need;
       }
+      else if (fl_string_dynamic_compare_string(controller_string_nice, cache->name_item, controller_string_nice_length) == F_equal_to) {
+        type = controller_rule_setting_type_nice;
+      }
       else if (fl_string_dynamic_compare_string(controller_string_parameter, cache->name_item, controller_string_parameter_length) == F_equal_to) {
         type = controller_rule_setting_type_parameter;
       }
       else if (fl_string_dynamic_compare_string(controller_string_path, cache->name_item, controller_string_path_length) == F_equal_to) {
         type = controller_rule_setting_type_path;
       }
+      else if (fl_string_dynamic_compare_string(controller_string_scheduler, cache->name_item, controller_string_scheduler_length) == F_equal_to) {
+        type = controller_rule_setting_type_scheduler;
+      }
       else if (fl_string_dynamic_compare_string(controller_string_script, cache->name_item, controller_string_script_length) == F_equal_to) {
         type = controller_rule_setting_type_script;
       }
+      else if (fl_string_dynamic_compare_string(controller_string_user, cache->name_item, controller_string_user_length) == F_equal_to) {
+        type = controller_rule_setting_type_user;
+      }
       else if (fl_string_dynamic_compare_string(controller_string_want, cache->name_item, controller_string_want_length) == F_equal_to) {
         type = controller_rule_setting_type_want;
       }
@@ -1637,10 +1737,13 @@ extern "C" {
       if (type == controller_rule_setting_type_define || type == controller_rule_setting_type_parameter) {
 
         if (cache->content_actions.array[i].used != 2) {
-          fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
-          fprintf(data.error.to.stream, "%s%sRule setting requires exactly two Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s, data.error.context.after->string, f_string_eol_s[0]);
 
-          controller_rule_error_print(data.error, *cache, F_false);
+          if (data.error.verbosity != f_console_verbosity_quiet) {
+            fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+            fprintf(data.error.to.stream, "%s%sRule setting requires exactly two Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s, data.error.context.after->string, f_string_eol_s[0]);
+
+            controller_rule_error_print(data.error, *cache, F_false);
+          }
 
           if (F_status_is_error_not(status_return)) {
             status_return = F_status_set_error(F_valid_not);
@@ -1723,9 +1826,9 @@ extern "C" {
         continue;
       }
 
-      if (type == controller_rule_setting_type_control_group || type == controller_rule_setting_type_name || type == controller_rule_setting_type_path || type == controller_rule_setting_type_script) {
-        if (type == controller_rule_setting_type_control_group) {
-          setting_value = &rule->control_group;
+      if (type == controller_rule_setting_type_control || type == controller_rule_setting_type_name || type == controller_rule_setting_type_path || type == controller_rule_setting_type_scheduler || type == controller_rule_setting_type_script) {
+        if (type == controller_rule_setting_type_control) {
+          setting_value = &rule->control;
         }
         else if (type == controller_rule_setting_type_name) {
           setting_value = &rule->name;
@@ -1733,15 +1836,21 @@ extern "C" {
         else if (type == controller_rule_setting_type_path) {
           setting_value = &rule->path;
         }
+        else if (type == controller_rule_setting_type_scheduler) {
+          setting_value = &rule->scheduler;
+        }
         else if (type == controller_rule_setting_type_script) {
           setting_value = &rule->script;
         }
 
         if (setting_value->used || cache->content_actions.array[i].used != 1) {
-          fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
-          fprintf(data.error.to.stream, "%s%sRule setting requires exactly one Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s, data.error.context.after->string, f_string_eol_s[0]);
 
-          controller_rule_error_print(data.error, *cache, F_false);
+          if (data.error.verbosity != f_console_verbosity_quiet) {
+            fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+            fprintf(data.error.to.stream, "%s%sRule setting requires exactly one Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s, data.error.context.after->string, f_string_eol_s[0]);
+
+            controller_rule_error_print(data.error, *cache, F_false);
+          }
 
           if (F_status_is_error_not(status_return)) {
             status_return = F_status_set_error(F_valid_not);
@@ -1750,9 +1859,7 @@ extern "C" {
           continue;
         }
 
-        setting_value->used = 0;
-
-        if (type == controller_rule_setting_type_control_group || type == controller_rule_setting_type_name || type == controller_rule_setting_type_script) {
+        if (type == controller_rule_setting_type_control || type == controller_rule_setting_type_name || type == controller_rule_setting_type_script) {
 
           status = controller_string_dynamic_rip_nulless_terminated(cache->buffer_item, cache->content_actions.array[i].array[0], setting_value);
 
@@ -1771,37 +1878,47 @@ extern "C" {
             continue;
           }
 
-          status = controller_validate_has_graph(*setting_value);
+          if (type == controller_rule_setting_type_control) {
+            // @todo validate that this is a valid path.
+            // @todo append setting.path_control, then path_separator, and then this string.
+            // @todo the control path doesn't have to exist just yet, but print a warning if it doesn't and debug is visible.
+          }
+          else if (type == controller_rule_setting_type_name || type == controller_rule_setting_type_script) {
+            status = controller_validate_has_graph(*setting_value);
+
+            if (status == F_false || F_status_set_fine(status) == F_complete_not_utf) {
+              if (status == F_false) {
 
-          if (status == F_false || F_status_set_fine(status) == F_complete_not_utf) {
-            if (status == F_false) {
-              fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
-              fprintf(data.error.to.stream, "%s%sRule setting has an invalid name '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s);
-              fprintf(data.error.to.stream, "%s%s", data.error.context.after->string, data.error.notable.before->string);
-              f_print_dynamic(data.error.to.stream, *setting_value);
-              fprintf(data.error.to.stream, "%s", data.error.notable.after->string);
-              fprintf(data.error.to.stream, "%s', there must be at least 1 graph character.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
+                if (data.error.verbosity != f_console_verbosity_quiet) {
+                  fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+                  fprintf(data.error.to.stream, "%s%sRule setting has an invalid name '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s);
+                  fprintf(data.error.to.stream, "%s%s", data.error.context.after->string, data.error.notable.before->string);
+                  f_print_dynamic(data.error.to.stream, *setting_value);
+                  fprintf(data.error.to.stream, "%s", data.error.notable.after->string);
+                  fprintf(data.error.to.stream, "%s', there must be at least 1 graph character.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
 
-              controller_rule_error_print(data.error, *cache, F_false);
+                  controller_rule_error_print(data.error, *cache, F_false);
+                }
 
-              if (F_status_is_error_not(status_return)) {
-                status_return = F_status_set_error(F_valid_not);
+                if (F_status_is_error_not(status_return)) {
+                  status_return = F_status_set_error(F_valid_not);
+                }
               }
-            }
-            else {
+              else {
 
-              // this function should only return F_complete_not_utf on error.
-              fll_error_print(data.error, F_complete_not_utf, "controller_validate_has_graph", F_true);
+                // this function should only return F_complete_not_utf on error.
+                fll_error_print(data.error, F_complete_not_utf, "controller_validate_has_graph", F_true);
 
-              if (F_status_is_error_not(status_return)) {
-                status_return = status;
+                if (F_status_is_error_not(status_return)) {
+                  status_return = status;
+                }
               }
-            }
 
-            setting_value->used = 0;
+              setting_value->used = 0;
 
-            controller_rule_error_print(data.error, *cache, F_false);
-            continue;
+              controller_rule_error_print(data.error, *cache, F_false);
+              continue;
+            }
           }
         }
         else if (type == controller_rule_setting_type_path) {
@@ -1833,6 +1950,281 @@ extern "C" {
             continue;
           }
         }
+        else if (type == controller_rule_setting_type_scheduler) {
+          // @todo
+        }
+
+        continue;
+      }
+
+      if (type == controller_rule_setting_type_capability || type == controller_rule_setting_type_nice || type == controller_rule_setting_type_user) {
+
+        if (cache->content_actions.array[i].used != 1 || type == controller_rule_setting_type_capability && rule->capability || type == controller_rule_setting_type_group && (rule->has & controller_rule_has_group) || type == controller_rule_setting_type_nice && (rule->has & controller_rule_has_nice) || type == controller_rule_setting_type_user && (rule->has & controller_rule_has_user)) {
+
+          if (data.error.verbosity != f_console_verbosity_quiet) {
+            fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+            fprintf(data.error.to.stream, "%s%sRule setting requires exactly one Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s, data.error.context.after->string, f_string_eol_s[0]);
+
+            controller_rule_error_print(data.error, *cache, F_false);
+          }
+
+          if (F_status_is_error_not(status_return)) {
+            status_return = F_status_set_error(F_valid_not);
+          }
+
+          continue;
+        }
+
+        if (type == controller_rule_setting_type_capability) {
+          cache->buffer_other.used = 0;
+
+          status = fl_string_dynamic_partial_append_nulless(cache->buffer_item, cache->content_actions.array[i].array[0], &cache->buffer_other);
+
+          if (F_status_is_error(status)) {
+            fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_partial_append_nulless", F_true);
+
+            controller_rule_error_print(data.error, *cache, F_false);
+
+            if (F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_memory_allocation || F_status_set_fine(status) == F_memory_reallocation) {
+              return status;
+            }
+
+            if (F_status_is_error_not(status_return)) {
+              status_return = F_status_set_error(F_valid_not);
+            }
+          }
+
+          status = fl_string_dynamic_terminate_after(&cache->buffer_other);
+
+          if (F_status_is_error(status)) {
+            fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_terminate_after", F_true);
+
+            controller_rule_error_print(data.error, *cache, F_false);
+
+            if (F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_memory_allocation || F_status_set_fine(status) == F_memory_reallocation) {
+              return status;
+            }
+
+            if (F_status_is_error_not(status_return)) {
+              status_return = F_status_set_error(F_valid_not);
+            }
+          }
+
+          status = f_capability_from_text(cache->buffer_other.string, &rule->capability);
+
+          if (F_status_is_error(status) && F_status_set_fine(status) != F_supported_not) {
+
+            if (F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_memory_allocation || F_status_set_fine(status) == F_memory_reallocation) {
+              fll_error_print(data.error, F_status_set_fine(status), "f_capability_from_text", F_true);
+              controller_rule_error_print(data.error, *cache, F_false);
+
+              return status;
+            }
+
+            if (data.error.verbosity != f_console_verbosity_quiet) {
+              fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+              fprintf(data.error.to.stream, "%s%sRule setting failed to process the capabilities.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s, data.error.context.after->string, f_string_eol_s[0]);
+
+              controller_rule_error_print(data.error, *cache, F_false);
+            }
+
+            if (F_status_is_error_not(status_return)) {
+              status_return = F_status_set_error(F_valid_not);
+            }
+
+            continue;
+          }
+        }
+        else if (type == controller_rule_setting_type_nice) {
+          f_number_signed_t number = 0;
+
+          status = fl_conversion_string_to_number_signed(cache->buffer_item.string, &number, cache->content_actions.array[i].array[0]);
+
+          if (F_status_is_error(status) || number < -20 || number > 19) {
+            status = F_status_set_fine(status);
+
+            if (number < -20 || number > 19 || status == F_data_not || status == F_number || status == F_number_overflow) {
+
+              if (data.error.verbosity != f_console_verbosity_quiet) {
+                fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+                fprintf(data.error.to.stream, "%s%sRule setting has an invalid number '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s);
+                fprintf(data.error.to.stream, "%s%s", data.error.context.after->string, data.error.notable.before->string);
+                f_print_dynamic_partial(data.error.to.stream, cache->buffer_item, cache->content_actions.array[i].array[0]);
+                fprintf(data.error.to.stream, "%s", data.error.notable.after->string);
+                fprintf(data.error.to.stream, "%s', only the whole numbers inclusively between ", data.error.context.before->string);
+                fprintf(data.error.to.stream, "%s%s-20%s", data.error.context.after->string, data.error.notable.before->string, data.error.notable.after->string);
+                fprintf(data.error.to.stream, "%s and ", data.error.context.before->string);
+                fprintf(data.error.to.stream, "%s%s19%s", data.error.context.after->string, data.error.notable.before->string, data.error.notable.after->string);
+                fprintf(data.error.to.stream, "%s are allowed.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
+
+                controller_rule_error_print(data.error, *cache, F_false);
+              }
+
+              if (F_status_is_error_not(status_return)) {
+                status_return = F_status_set_error(F_valid_not);
+              }
+            }
+            else {
+              fll_error_print(data.error, status, "fl_conversion_string_to_number_signed", F_true);
+              status = F_status_set_error(status);
+            }
+          }
+          else {
+            rule->nice = number;
+            rule->has |= controller_rule_has_nice;
+          }
+        }
+        else if (type == controller_rule_setting_type_user) {
+          uid_t number = 0;
+
+          status = controller_get_id_user(cache->buffer_item, cache->content_actions.array[i].array[0], cache, &number);
+
+          if (F_status_is_error(status)) {
+            status = F_status_set_fine(status);
+
+            if (status == F_exist_not) {
+              if (data.error.verbosity != f_console_verbosity_quiet) {
+                fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+                fprintf(data.error.to.stream, "%s%sRule setting has an invalid user '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s);
+                fprintf(data.error.to.stream, "%s%s", data.error.context.after->string, data.error.notable.before->string);
+                f_print_dynamic_partial(data.error.to.stream, cache->buffer_item, cache->content_actions.array[i].array[0]);
+                fprintf(data.error.to.stream, "%s", data.error.notable.after->string);
+                fprintf(data.error.to.stream, "%s' because no user was found by that name.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
+              }
+            }
+            else if (status == F_number_too_large) {
+              if (data.error.verbosity != f_console_verbosity_quiet) {
+                fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+                fprintf(data.error.to.stream, "%s%sRule setting has an invalid user '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s);
+                fprintf(data.error.to.stream, "%s%s", data.error.context.after->string, data.error.notable.before->string);
+                f_print_dynamic_partial(data.error.to.stream, cache->buffer_item, cache->content_actions.array[i].array[0]);
+                fprintf(data.error.to.stream, "%s", data.error.notable.after->string);
+                fprintf(data.error.to.stream, "%s' because the given ID is too large.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
+              }
+            }
+            else if (status == F_number) {
+              if (data.error.verbosity != f_console_verbosity_quiet) {
+                fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+                fprintf(data.error.to.stream, "%s%sRule setting has an invalid user '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s);
+                fprintf(data.error.to.stream, "%s%s", data.error.context.after->string, data.error.notable.before->string);
+                f_print_dynamic_partial(data.error.to.stream, cache->buffer_item, cache->content_actions.array[i].array[0]);
+                fprintf(data.error.to.stream, "%s", data.error.notable.after->string);
+                fprintf(data.error.to.stream, "%s' because the given ID is not a valid supported number.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
+              }
+            }
+            else {
+              fll_error_print(data.error, status, "f_account_id_user_by_name", F_true);
+            }
+
+            controller_rule_error_print(data.error, *cache, F_false);
+
+            if (F_status_is_error_not(status_return)) {
+              status_return = F_status_set_error(status);
+            }
+          }
+          else {
+            rule->user = number;
+            rule->has |= controller_rule_has_user;
+          }
+        }
+
+        continue;
+      }
+
+      if (type == controller_rule_setting_type_group) {
+        if (!cache->content_actions.array[i].used) {
+          if (data.error.verbosity != f_console_verbosity_quiet) {
+            fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+            fprintf(data.error.to.stream, "%s%sRule setting requires one or more Content.%s%c", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s, data.error.context.after->string, f_string_eol_s[0]);
+
+            controller_rule_error_print(data.error, *cache, F_false);
+          }
+
+          if (F_status_is_error_not(status_return)) {
+            status_return = F_status_set_error(F_valid_not);
+          }
+
+          continue;
+        }
+
+        gid_t number = 0;
+
+        rule->groups.used = 0;
+
+        for (j = 0; j < cache->content_actions.array[i].used; ++j) {
+
+          status = fl_type_int32s_increase(&rule->groups);
+
+          if (F_status_is_error(status)) {
+            fll_error_print(data.error, F_status_set_fine(status), "fl_type_int32s_increase", F_true);
+
+            if (F_status_set_fine(status) == F_memory_not || F_status_set_fine(status) == F_memory_allocation || F_status_set_fine(status) == F_memory_reallocation) {
+              return status;
+            }
+
+            if (F_status_is_error_not(status_return)) {
+              status_return = status;
+            }
+
+            controller_rule_error_print(data.error, *cache, F_false);
+            continue;
+          }
+
+          status = controller_get_id_group(cache->buffer_item, cache->content_actions.array[i].array[j], cache, &number);
+
+          if (F_status_is_error(status)) {
+            status = F_status_set_fine(status);
+
+            if (status == F_exist_not) {
+              if (data.error.verbosity != f_console_verbosity_quiet) {
+                fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+                fprintf(data.error.to.stream, "%s%sRule setting has an invalid group '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s);
+                fprintf(data.error.to.stream, "%s%s", data.error.context.after->string, data.error.notable.before->string);
+                f_print_dynamic_partial(data.error.to.stream, cache->buffer_item, cache->content_actions.array[i].array[j]);
+                fprintf(data.error.to.stream, "%s", data.error.notable.after->string);
+                fprintf(data.error.to.stream, "%s' because no group was found by that name.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
+              }
+            }
+            else if (status == F_number_too_large) {
+              if (data.error.verbosity != f_console_verbosity_quiet) {
+                fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+                fprintf(data.error.to.stream, "%s%sRule setting has an invalid group '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s);
+                fprintf(data.error.to.stream, "%s%s", data.error.context.after->string, data.error.notable.before->string);
+                f_print_dynamic_partial(data.error.to.stream, cache->buffer_item, cache->content_actions.array[i].array[j]);
+                fprintf(data.error.to.stream, "%s", data.error.notable.after->string);
+                fprintf(data.error.to.stream, "%s' because the given ID is too large.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
+              }
+            }
+            else if (status == F_number) {
+              if (data.error.verbosity != f_console_verbosity_quiet) {
+                fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+                fprintf(data.error.to.stream, "%s%sRule setting has an invalid group '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s);
+                fprintf(data.error.to.stream, "%s%s", data.error.context.after->string, data.error.notable.before->string);
+                f_print_dynamic_partial(data.error.to.stream, cache->buffer_item, cache->content_actions.array[i].array[j]);
+                fprintf(data.error.to.stream, "%s", data.error.notable.after->string);
+                fprintf(data.error.to.stream, "%s' because the given ID is not a valid supported number.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
+              }
+            }
+            else {
+              fll_error_print(data.error, status, "f_account_id_group_by_name", F_true);
+            }
+
+            controller_rule_error_print(data.error, *cache, F_false);
+
+            if (F_status_is_error_not(status_return)) {
+              status_return = F_status_set_error(status);
+            }
+          }
+          else {
+            if (rule->has & controller_rule_has_group) {
+              rule->groups.array[rule->groups.used++] = number;
+            }
+            else {
+              rule->group = number;
+              rule->has |= controller_rule_has_group;
+            }
+          }
+        } // for
 
         continue;
       }
@@ -1893,12 +2285,15 @@ extern "C" {
 
           if (status == F_false || F_status_set_fine(status) == F_complete_not_utf) {
             if (status == F_false) {
-              fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
-              fprintf(data.error.to.stream, "%s%sRule setting has an invalid environment variable name '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s);
-              fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, setting_values->array[setting_values->used].string, data.error.notable.after->string);
-              fprintf(data.error.to.stream, "%s'.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
 
-              controller_rule_error_print(data.error, *cache, F_false);
+              if (data.error.verbosity != f_console_verbosity_quiet) {
+                fprintf(data.error.to.stream, "%c", f_string_eol_s[0]);
+                fprintf(data.error.to.stream, "%s%sRule setting has an invalid environment variable name '", data.error.context.before->string, data.error.prefix ? data.error.prefix : f_string_empty_s);
+                fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, setting_values->array[setting_values->used].string, data.error.notable.after->string);
+                fprintf(data.error.to.stream, "%s'.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
+
+                controller_rule_error_print(data.error, *cache, F_false);
+              }
 
               if (F_status_is_error_not(status_return)) {
                 status_return = F_status_set_error(F_valid_not);
@@ -2035,7 +2430,7 @@ extern "C" {
 #endif // _di_controller_rule_setting_read_
 
 #ifndef _di_controller_rule_simulate_
-  void controller_rule_simulate(const controller_data_t data, const controller_cache_t cache, const f_array_length_t index, const uint8_t action, const uint8_t options, controller_setting_t *setting) {
+  void controller_rule_simulate(const controller_data_t data, const f_array_length_t index, const uint8_t action, const uint8_t options, controller_cache_t *cache, controller_setting_t *setting) {
 
     switch (action) {
       case controller_rule_action_type_kill:
@@ -2053,7 +2448,7 @@ extern "C" {
           fprintf(data.error.to.stream, "%s%s%s%s", data.error.context.after->string, data.error.notable.before->string, controller_rule_action_type_name(action).string, data.error.notable.after->string);
           fprintf(data.error.to.stream, "%s' while attempting to simulate rule execution.%s%c", data.error.context.before->string, data.error.context.after->string, f_string_eol_s[0]);
 
-          controller_rule_error_print(data.error, cache, F_true);
+          controller_rule_error_print(data.error, *cache, F_true);
         }
 
         return;
@@ -2098,7 +2493,41 @@ extern "C" {
     fprintf(data.output.stream, "  %s%s%s %s%c", data.context.set.important.before->string, controller_string_name, data.context.set.important.after->string, rule->name.used ? rule->name.string : f_string_empty_s, f_string_eol_s[0]);
     fprintf(data.output.stream, "  %s%s%s %s%c", data.context.set.important.before->string, controller_string_how, data.context.set.important.after->string, options & controller_rule_option_asynchronous ? controller_string_asynchronous : controller_string_synchronous, f_string_eol_s[0]);
     fprintf(data.output.stream, "  %s%s%s %s%c", data.context.set.important.before->string, controller_string_wait, data.context.set.important.after->string, options & controller_rule_option_wait ? controller_string_yes : controller_string_no, f_string_eol_s[0]);
-    fprintf(data.output.stream, "  %s%s%s %s%c", data.context.set.important.before->string, controller_string_control_group, data.context.set.important.after->string, rule->control_group.used ? rule->control_group.string : f_string_empty_s, f_string_eol_s[0]);
+
+    if (f_capability_supported()) {
+      fprintf(data.output.stream, "  %s%s%s ", data.context.set.important.before->string, controller_string_capability, data.context.set.important.after->string);
+
+      if (rule->capability) {
+        cache->buffer_other.used = 0;
+
+        if (F_status_is_error_not(f_capability_to_text(rule->capability, &cache->buffer_other))) {
+          fprintf(data.output.stream, "%s", cache->buffer_other.string);
+        }
+      }
+
+      fprintf(data.output.stream, "%c", f_string_eol_s[0]);
+    }
+    else {
+      fprintf(data.output.stream, "  %s%s%s ", data.context.set.important.before->string, controller_string_capability, data.context.set.important.after->string, f_string_eol_s[0]);
+      fprintf(data.output.stream, "%s(unsupported)%s%c", data.context.set.warning.before->string, data.context.set.warning.after->string, f_string_eol_s[0]);
+    }
+
+    fprintf(data.output.stream, "  %s%s%s %s%c", data.context.set.important.before->string, controller_string_control, data.context.set.important.after->string, rule->control.used ? rule->control.string : f_string_empty_s, f_string_eol_s[0]);
+    fprintf(data.output.stream, "  %s%s%s %s%c", data.context.set.important.before->string, controller_string_path, data.context.set.important.after->string, rule->path.used ? rule->path.string : f_string_empty_s, f_string_eol_s[0]);
+    fprintf(data.output.stream, "  %s%s%s %s%c", data.context.set.important.before->string, controller_string_scheduler, data.context.set.important.after->string, rule->scheduler.used ? rule->scheduler.string : f_string_empty_s, f_string_eol_s[0]);
+    fprintf(data.output.stream, "  %s%s%s %s%c", data.context.set.important.before->string, controller_string_script, data.context.set.important.after->string, rule->script.used ? rule->script.string : f_string_empty_s, f_string_eol_s[0]);
+
+    fprintf(data.output.stream, "  %s%s%s", data.context.set.important.before->string, controller_string_nice, data.context.set.important.after->string);
+    if (rule->has & controller_rule_has_nice) {
+      fprintf(data.output.stream, " %i", rule->nice);
+    }
+    fprintf(data.output.stream, "%c", f_string_eol_s[0]);
+
+    fprintf(data.output.stream, "  %s%s%s", data.context.set.important.before->string, controller_string_user, data.context.set.important.after->string);
+    if (rule->has & controller_rule_has_user) {
+      fprintf(data.output.stream, " %i", rule->user);
+    }
+    fprintf(data.output.stream, "%c", f_string_eol_s[0]);
 
     fprintf(data.output.stream, "  %s%s%s {%c", data.context.set.important.before->string, controller_string_define, data.context.set.important.after->string, f_string_eol_s[0]);
 
@@ -2113,27 +2542,26 @@ extern "C" {
 
     fprintf(data.output.stream, "  }%c", f_string_eol_s[0]);
 
-    fprintf(data.output.stream, "  %s%s%s {%c", data.context.set.important.before->string, controller_string_parameter, data.context.set.important.after->string, f_string_eol_s[0]);
+    fprintf(data.output.stream, "  %s%s%s {%c", data.context.set.important.before->string, controller_string_environment, data.context.set.important.after->string, f_string_eol_s[0]);
 
-    if (rule->parameter.used) {
-      for (i = 0; i < rule->parameter.used; ++i) {
+    if (rule->environment.used) {
+      for (i = 0; i < rule->environment.used; ++i) {
 
-        if (rule->parameter.array[i].name.used && rule->parameter.array[i].value.used) {
-          fprintf(data.output.stream, "    %s %s=%s %s%c", rule->parameter.array[i].name.string, data.context.set.important.before->string, data.context.set.important.after->string, rule->parameter.array[i].value.string, f_string_eol_s[0]);
+        if (rule->environment.array[i].used) {
+          fprintf(data.output.stream, "    %s%c", rule->environment.array[i].string, f_string_eol_s[0]);
         }
       } // for
     }
 
     fprintf(data.output.stream, "  }%c", f_string_eol_s[0]);
 
-    fprintf(data.output.stream, "  %s%s%s {%c", data.context.set.important.before->string, controller_string_environment, data.context.set.important.after->string, f_string_eol_s[0]);
+    fprintf(data.output.stream, "  %s%s%s {%c", data.context.set.important.before->string, controller_string_group, data.context.set.important.after->string, f_string_eol_s[0]);
 
-    if (rule->environment.used) {
-      for (i = 0; i < rule->environment.used; ++i) {
+    if (rule->has & controller_rule_has_group) {
+      fprintf(data.output.stream, "    %i%c", rule->group, f_string_eol_s[0]);
 
-        if (rule->environment.array[i].used) {
-          fprintf(data.output.stream, "    %s%c", rule->environment.array[i].string, f_string_eol_s[0]);
-        }
+      for (i = 0; i < rule->groups.used; ++i) {
+        fprintf(data.output.stream, "    %i%c", rule->groups.array[i], f_string_eol_s[0]);
       } // for
     }
 
@@ -2152,6 +2580,19 @@ extern "C" {
 
     fprintf(data.output.stream, "  }%c", f_string_eol_s[0]);
 
+    fprintf(data.output.stream, "  %s%s%s {%c", data.context.set.important.before->string, controller_string_parameter, data.context.set.important.after->string, f_string_eol_s[0]);
+
+    if (rule->parameter.used) {
+      for (i = 0; i < rule->parameter.used; ++i) {
+
+        if (rule->parameter.array[i].name.used && rule->parameter.array[i].value.used) {
+          fprintf(data.output.stream, "    %s %s=%s %s%c", rule->parameter.array[i].name.string, data.context.set.important.before->string, data.context.set.important.after->string, rule->parameter.array[i].value.string, f_string_eol_s[0]);
+        }
+      } // for
+    }
+
+    fprintf(data.output.stream, "  }%c", f_string_eol_s[0]);
+
     fprintf(data.output.stream, "  %s%s%s {%c", data.context.set.important.before->string, controller_string_want, data.context.set.important.after->string, f_string_eol_s[0]);
 
     if (rule->want.used) {
index 81e4f6f003b71b9fbea9bf07df5b18d7a1c70d5a..3f67e1c6c5f67a089c7a3bb3508ccf3f2db38ae3 100644 (file)
@@ -261,6 +261,8 @@ extern "C" {
  *   @todo this is not yet implemented.
  * @param parameter
  *   The execute parameter settings.
+ * @param as
+ *   The execute as settings.
  * @param data
  *   The program data.
  *
@@ -275,7 +277,7 @@ extern "C" {
  * @see fll_execute_program()
  */
 #ifndef _di_controller_rule_execute_pid_with_
-  extern f_return_status controller_rule_execute_pid_with(const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, fl_execute_parameter_t * const parameter, controller_data_t *data) f_gcc_attribute_visibility_internal;
+  extern f_return_status controller_rule_execute_pid_with(const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, fl_execute_parameter_t * const parameter, fl_execute_as_t * const as, controller_data_t *data) f_gcc_attribute_visibility_internal;
 #endif // _di_controller_rule_execute_pid_with_
 
 /**
@@ -302,6 +304,8 @@ extern "C" {
  *   @todo this is not yet implemented.
  * @param parameter
  *   The execute parameter settings.
+ * @param as
+ *   The execute as settings.
  * @param data
  *   The program data.
  *
@@ -315,7 +319,7 @@ extern "C" {
  * @see fll_execute_program()
  */
 #ifndef _di_controller_rule_execute_foreground_
-  extern f_return_status controller_rule_execute_foreground(const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, fl_execute_parameter_t * const parameter, controller_data_t *data) f_gcc_attribute_visibility_internal;
+  extern f_return_status controller_rule_execute_foreground(const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, fl_execute_parameter_t * const parameter, fl_execute_as_t * const as, controller_data_t *data) f_gcc_attribute_visibility_internal;
 #endif // _di_controller_rule_execute_foreground_
 
 /**
@@ -552,6 +556,8 @@ extern "C" {
  *
  * @param data
  *   The program data.
+ * @param setting
+ *   The controller settings data.
  * @param cache
  *   A structure for containing and caching relevant data.
  * @param rule
@@ -576,7 +582,7 @@ extern "C" {
  * @see fll_path_canonical()
  */
 #ifndef _di_controller_rule_setting_read_
-  extern f_return_status controller_rule_setting_read(const controller_data_t data, controller_cache_t *cache, controller_rule_t *rule) f_gcc_attribute_visibility_internal;
+  extern f_return_status controller_rule_setting_read(const controller_data_t data, const controller_setting_t setting, controller_cache_t *cache, controller_rule_t *rule) f_gcc_attribute_visibility_internal;
 #endif // _di_controller_rule_setting_read_
 
 /**
@@ -588,10 +594,10 @@ extern "C" {
  *
  * @param data
  *   The program data.
- * @param cache
- *   A structure for containing and caching relevant data.
  * @param index
  *   The position in the setting.rules array representing the rule to simulate.
+ * @param cache
+ *   A structure for containing and caching relevant data.
  * @param action
  *   The action to perform based on the action type codes.
  *
@@ -610,7 +616,7 @@ extern "C" {
  *   The controller settings data.
  */
 #ifndef _di_controller_rule_simulate_
-  extern void controller_rule_simulate(const controller_data_t data, const controller_cache_t cache, const f_array_length_t index, const uint8_t action, const uint8_t options, controller_setting_t *setting) f_gcc_attribute_visibility_internal;
+  extern void controller_rule_simulate(const controller_data_t data, const f_array_length_t index, const uint8_t action, const uint8_t options, controller_cache_t *cache, controller_setting_t *setting) f_gcc_attribute_visibility_internal;
 #endif // _di_controller_rule_simulate_
 
 /**
index c6653172ef1e71eb1aff738b1cbad4300feeacd6..903c38c833c065f69dcff069c87eb4b052c103ab 100644 (file)
@@ -1,2 +1,2 @@
 # fss-0000
-
+_di_libcap_ Disable libcap support, allow for compiling and linking without libcap (-lcap).
index 0adc37e46d82aad4bf958ead34e073819c279ffb..5af11e3f95affe7a35a3ff79f442718022cf7c5f 100644 (file)
@@ -5,6 +5,8 @@ f_status
 f_memory
 f_string
 f_utf
+f_account
+f_capability
 f_color
 f_console
 f_conversion
index 20a49be9393d63c17d26852a14dfb4402013eb60..5e3ed2bff8d96b4980a79a683e7b1d560933af17 100644 (file)
@@ -18,8 +18,8 @@ modes_default monolithic
 build_compiler gcc
 build_indexer ar
 build_language c
-build_libraries -lc
-build_libraries-individual -lfll_environment -lfll_error -lfll_execute -lfll_fss -lfll_path -lfll_program -lfll_status -lfl_color -lfl_console -lfl_conversion -lfl_environment -lfl_fss -lfl_iki -lfl_status -lfl_string -lfl_type -lf_console -lf_conversion -lf_directory -lf_environment -lf_file -lf_fss -lf_iki -lf_memory -lf_path -lf_pipe -lf_print -lf_signal -lf_utf
+build_libraries -lc -lcap
+build_libraries-individual -lfll_environment -lfll_error -lfll_execute -lfll_fss -lfll_path -lfll_program -lfll_status -lfl_color -lfl_console -lfl_conversion -lfl_environment -lfl_fss -lfl_iki -lfl_status -lfl_string -lfl_type -lf_account -lf_capability -lf_console -lf_conversion -lf_directory -lf_environment -lf_file -lf_fss -lf_iki -lf_memory -lf_path -lf_pipe -lf_print -lf_signal -lf_utf
 build_libraries-level -lfll_2 -lfll_1 -lfll_0
 build_libraries-monolithic -lfll
 build_sources_library controller.c private-control.c private-controller.c private-entry.c private-rule.c
@@ -46,6 +46,7 @@ search_exclusive yes
 search_shared yes
 search_static yes
 
+#defines_all -D_di_libcap_
 defines_all
 defines_static
 defines_shared
index dfc6144030e3f4d90019f86cadf32e8311a20ae0..b2a2bcb23e2062219887f4f880435f0064c5dd5d 100644 (file)
@@ -1,7 +1,17 @@
 # fss-000d
 
 setting:
-  name "Multiple Commands: whoami and date"
+  name "Multiple Commands: id, whoami, date, etc.."
+  capability "all="
+  nice 15
+  #user kevin
+  #group list 8 root
+
+command:
+  start {
+    id
+    sleep 20
+  }
 
 command:
   start whoami
index 25339ad36c3a6c4340b558dfa7ac5879f8bd3a25..c4d3b6e0e153f6ea13b7308b847270d37ef03bae 100644 (file)
@@ -5,24 +5,24 @@
 
 setting:
   name "System Terminal"
+  capability "all="
 
-service: 
+service:
   use /var/run/tty/tty1.pid
 
   start qingy tty1 -d -l -n -t
-    
+
 service:
   use /var/run/tty/tty2.pid
 
   start qingy tty2 -d -l -n -t
-      
+
 service:
   use /var/run/tty/tty3.pid
 
   start qingy tty3 -d -l -n -t
-        
+
 service:
   use /var/run/tty/tty4.pid
 
   start qingy tty4 -d -l -n -t
-
index 5a551ab7b8188004b0df465638743c408c4edd99..ed434be5d76e9d263fc65501c45d591a399d0c2e 100644 (file)
@@ -5,6 +5,8 @@
 
 setting:
   name "D-BUS"
+  capability "all="
+  nice 15
 
 service:
   use /var/run/dbus/dbus.pid
index 91c92de6cda7ee075fcbbaf2654a34c06cee9c17..4c650929f66c122e7b62d73cf54ae2d0be8e26c7 100644 (file)
@@ -5,6 +5,8 @@
 
 setting:
   name "System Logger"
+  capability "all="
+  nice 19
 
 service:
   # @todo consider adding support for IKI to make "/var/run/logger/logger.pid" a variable.
index 7e759f11d12ff526328f93304db73af1a603b033..f2e0061a850daa001ba8266e5539910d13d030d6 100644 (file)
@@ -5,6 +5,8 @@
 
 setting:
   name "Console Mouse"
+  capability "all="
+  nice 15
 
   # @todo consider adding iki support.
 
index a7014c6fcfe373fff0e0108be4a0ab8c2cb32db0..f0c789daa7e161b7f7d69e4b88e28ba05ea2b928 100644 (file)
@@ -5,6 +5,8 @@
 
 setting:
   name "Setup Clock"
+  capability "all="
+  nice 15
 
 script:
   start {
@@ -13,7 +15,7 @@ script:
     if [[ -f /etc/clock ]] ; then
       clock_mode=$(fss_basic_read -c 0 -n mode /etc/clock);
     fi
-  
+
     if [[ $clock_mode == "local" ]] ; then
       hwclock --hctosys;
     elif [[ $clock_mode == "ntpdate" ]] ; then
index 862f4c9ee7f005c740e88bc0d0683dd492de54f2..07edc8a82e17e9462be50959656ba77733db3640 100644 (file)
@@ -5,3 +5,5 @@
 
 setting:
   name "System Keyboard"
+  capability "all="
+  nice 15
index 4836c2fa3054b1a5aa7f1094b0164666aca5b42d..9a1aa027fe451bd5371f2ad0ec1b939cdb0594ce 100644 (file)
@@ -9,17 +9,29 @@ Rule Documentation:
   Multiple outer most list Objects may be specified and they are executed as provided, in a top-down manner.
 
   The "settings" Rule Type has the following FSS-0001 (Extended) Content\:
-    "control_group": Define a control group (cgroup) in which everything within this rule executes under.
+    "capability": Define a set of capabilities in which to use, using the capability "text" format (such as "= cap_chown+ep").
+    "control": Define a control group (cgroup) in which everything within this rule executes under.
     "define": Define a custom environment variable with a given variable, and automatically expose it to processes executed within this rule.
     "environment": A set of environment variables to expose to the processes executed within this rule (PATH is always exposed).
+    "group": A set of group names or IDs to execute as with the first group being the primary group and all remaining being supplementary groups.
     "name": A name used to represent this rule, which is printed to the user, screen, logs, etc...
     "need": A single rule required to be executed (must exist and must succeed) before this rule starts.
+    "nice": A single niceness value to run all processes executed within this rule as (-20 gets to be greediest in CPU usage and 19 being the nicest in CPU usage).
     "parameter": A statically defined IKI name and its associated value for use in this rule file.
     "path": A single Content used to set a custom PATH environment variable value.
     "script": An executable name of a script, such as "bash", to use for the "script" Rule Type (which likely defaults to "bash" if not specified).
+    "scheduler": A valid name of a scheduler to use.
+    "user": A single user name or ID to execute as.
     "want": A single rule desired to be executed (may exist and must succeed) before this rule starts.
     "wish": A single rule desired to be executed (may exist and is not required to succeed) before this rule starts.
 
+  In the case of "capability", if the user the controller program is run as does not have the desired capabilities already, they cannot be added.
+  This essentially maintains or reduces the capabilities already available.
+  Due to capabilities only being a draft in the POSIX standard, one may expect "capabilities" support may not be available and in such a case this setting will do nothing.
+  If the dependent project (f_capability) does not have libcap support enabled, then capabilities will be unsupported by the compilation of this project.
+
+  In the case of "group" and "user", only users and groups that the user the controller program is being run as may be used.
+
   In the case of "want" and "wish", if the desired rule is either not found or is otherwise disabled, then this will not fail or otherwise block the wanting or wishing rule.
 
   In the case of "path", when specified, the PATH environment variable is automatically added to the "environment" setting.
@@ -55,10 +67,14 @@ Rule Documentation:
   When "reload", "start", or "stop" Content are not provided, then no respective action is performed.
   Commands are conditionally available depending on the presence of these, such as if "stop" is not provided then "stop" (and "restart") will not be available for the "control" program(s) to use.
 
-  The "group" inner Content, an associated "command", "service", or "script" are executed with that group ID or group name.
-  The "user" inner Content, an associated "command", "service", or "script" are executed with that user ID or user name.
-  The "group" and "user" can only be switched to if the user this controller program being operated under is allowed to switch to.
-
   The "create" Content designates that this controller program to create the PID file after successfully starting the service.
   The "use" Content designates that the called program will provide the PID file after successfully starting the service.
   For both "create" and "program" the PID file is expected to only exist on success or failure and the existence thereof designates the success or failure rate.
+
+  The following Content are the same as those specified in the Settings above except that they apply to a specific Rule Item instead of all Rule Items in the file\:
+  - "capability"
+  - "control"
+  - "group"
+  - "nice"
+  - "scheduler"
+  - "user"
index 7de6cc0321f2c9ad804d88b7189960a6ab6bdec7..a7ae7ae8c3022470cd64ed62bd8a4ddbd3c3fde7 100644 (file)
@@ -28,38 +28,39 @@ Rule Specification:
   The other Rule Types are processed top-down.
 
   The "settings" Rule Type has the following FSS-0001 (Extended)\:
-    "control_group": One Content representing a valid control group (cgroup) name, must have at least 1 graph character (non-whitespace printing character) (leading and trailing whitespace are trimmed off).
+    "capability": One Content representing capabilities.
+    "control": One Content representing a valid control group (cgroup) name, must have at least 1 graph character (non-whitespace printing character) (leading and trailing whitespace are trimmed off).
     "define": Two Content, the first Content must be a case-sensitive valid environment variable name (alpha-numeric or underscore, but no leading digits).
     "environment": Zero or more Content, each must be a case-sensitive valid environment variable name (alpha-numeric or underscore, but no leading digits).
+    "group": One or more Content representing group names or group ids.
     "name": One Content, must have at least 1 graph character (non-whitespace printing character) (leading and trailing whitespace are trimmed off).
     "need": Two Content, the first being a partial path and the second being a rule file name without extension (such as "boot" "modules").
+    "nice": One Content, must be a valid number for process "niceness" (Any whole number inclusively between -20 to 19).
     "parameter": Two Content, the first Content must be a case-sensitive valid IKI name and the second being an IKI value.
     "path": One Content representing a valid PATH environment string (such as "/bin:/sbin:/usr/bin").
+    "scheduler": One Content representing a scheduler name.
     "script": One Content representing a valid program name or path (such as "bash" or "/bin/bash").
+    "user": One Content representing a user name or user id.
     "want": Two Content, the first being a partial path and the second being a rule file name without extension (such as "boot" "modules").
     "wish": Two Content, the first being a partial path and the second being a rule file name without extension (such as "boot" "modules").
 
   The "service" Rule Type allows the following the FSS-0001 (Extended)\:
     "create": One Content representing the path to a PID file.
-    "group": One Content representing a group name or group id.
     "kill": One or more Content representing a program being executed and its arguments.
     "restart": One or more Content representing a program being executed and its arguments.
     "reload": One or more Content representing a program being executed and its arguments.
     "start": One or more Content representing a program being executed and its arguments.
     "stop": One or more Content representing a program being executed and its arguments.
     "use": One Content representing the path to a PID file.
-    "user": One Content representing a user name or user id.
 
   The "command" and "script" Rule Types allow the following the FSS-0001 (Extended)\:
-    "group": One Content representing a group name or group id.
     "kill": One or more Content representing a program being executed and its arguments.
     "restart": One or more Content representing a program being executed and its arguments.
     "reload": One or more Content representing a program being executed and its arguments.
     "start": One or more Content representing a program being executed and its arguments.
     "stop": One or more Content representing a program being executed and its arguments.
-    "user": One Content representing a user name or user id.
 
-  The "command", "script", and "service" Rule Types allow the following the FSS-0003 (Extended List)\:
+  The "command" and "service" Rule Types allow the following the FSS-0003 (Extended List)\:
     "kill": A list repesenting multiple programs and their respective arguments to execute.
     "restart": A list repesenting multiple programs and their respective arguments to execute.
     "reload": A list repesenting multiple programs and their respective arguments to execute.
index cd0d6439fa629682840f492b0100444a8a6e0b23..036022b7eb0af9d04e337c094ece6c2b1728ced2 100644 (file)
@@ -25,6 +25,8 @@ extern "C" {
       memcpy(build_libraries + fake_build_parameter_library_link_path_length, data.path_build_libraries_static.string, data.path_build_libraries_static.used);
     }
 
+    build_libraries[build_libraries_length] = 0;
+
     f_string_length_t build_includes_length = fake_build_parameter_library_include_length + data.path_build_includes.used;
 
     char build_includes[build_includes_length + 1];
@@ -1545,6 +1547,8 @@ extern "C" {
     *status = fll_fss_snatch_apart(buffer, objects, contents, settings_name, settings_length, fake_build_setting_total, settings_value, 0);
 
     if (*status == F_none) {
+      const int total_build_libraries = setting->build_libraries.used;
+
       f_string_dynamic_t settings_mode_name_dynamic[fake_build_setting_total];
       f_string_t settings_mode_names[fake_build_setting_total];
       f_string_length_t setting_mode_lengths[fake_build_setting_total];
@@ -1623,6 +1627,29 @@ extern "C" {
 
         if (F_status_is_error(*status)) break;
       } // for
+
+      // "build_libaries" is appended after all modes to help assist with static linker file issues (@todo there should likely be more options to have a postfix linker parameter that can be added here instead, such as "build_libraries_last").
+      if (total_build_libraries) {
+        f_string_dynamic_t temporary[total_build_libraries];
+
+        for (i = 0; i < total_build_libraries; ++i) {
+          temporary[i].string = setting->build_libraries.array[i].string;
+          temporary[i].used = setting->build_libraries.array[i].used;
+          temporary[i].size = setting->build_libraries.array[i].size;
+        } // for
+
+        for (i = 0, j = total_build_libraries; j < setting->build_libraries.used; ++i, ++j) {
+          setting->build_libraries.array[i].string = setting->build_libraries.array[j].string;
+          setting->build_libraries.array[i].used = setting->build_libraries.array[j].used;
+          setting->build_libraries.array[i].size = setting->build_libraries.array[j].size;
+        } // for
+
+        for (i = setting->build_libraries.used - total_build_libraries, j = 0; j < total_build_libraries; ++i, ++j) {
+          setting->build_libraries.array[i].string = temporary[j].string;
+          setting->build_libraries.array[i].used = temporary[j].used;
+          setting->build_libraries.array[i].size = temporary[j].size;
+        } // for
+      }
     }
 
     if (F_status_is_error(*status)) {
index 4f130804d83cb5bf412c3e349a4ac790b2b825ca..903c38c833c065f69dcff069c87eb4b052c103ab 100644 (file)
@@ -1 +1,2 @@
 # fss-0000
+_di_libcap_ Disable libcap support, allow for compiling and linking without libcap (-lcap).
index 6719e57aac487a6dd94e01f36b0dc493cb40a750..015d5796584983eeead8fbd7e280619b196e5730 100644 (file)
@@ -6,6 +6,7 @@ f_memory
 f_string
 f_utf
 f_account
+f_capability
 f_color
 f_console
 f_conversion
index 9d9104c69c6e7762ebfb2c94ccea9f26392a86bc..4385448590af1cbb43e374ea6d7d13f4eb2ce6b3 100644 (file)
@@ -18,8 +18,8 @@ modes_default monolithic
 build_compiler gcc
 build_indexer ar
 build_language c
-build_libraries -lc
-build_libraries-individual -lfll_environment -lfll_error -lfll_execute -lfll_file -lfll_fss -lfll_path -lfll_program -lfl_color -lfl_console -lfl_conversion -lfl_directory -lfl_environment -lfl_fss -lfl_iki -lfl_status -lfl_string -lfl_utf -lf_account -lf_console -lf_conversion -lf_directory -lf_environment -lf_file -lf_fss -lf_iki -lf_memory -lf_path -lf_print -lf_signal -lf_utf
+build_libraries -lc -lcap
+build_libraries-individual -lfll_environment -lfll_error -lfll_execute -lfll_file -lfll_fss -lfll_path -lfll_program -lfl_color -lfl_console -lfl_conversion -lfl_directory -lfl_environment -lfl_fss -lfl_iki -lfl_status -lfl_string -lfl_utf -lf_account -lf_capability -lf_console -lf_conversion -lf_directory -lf_environment -lf_file -lf_fss -lf_iki -lf_memory -lf_path -lf_print -lf_signal -lf_utf
 build_libraries-level -lfll_2 -lfll_1 -lfll_0
 build_libraries-monolithic -lfll
 build_sources_library fake.c private-fake.c private-clean.c private-build.c private-make.c private-print.c private-skeleton.c
@@ -46,6 +46,7 @@ search_exclusive yes
 search_shared yes
 search_static yes
 
+#defines_all -D_di_libcap_
 defines_all
 defines_static
 defines_shared
index 4f130804d83cb5bf412c3e349a4ac790b2b825ca..903c38c833c065f69dcff069c87eb4b052c103ab 100644 (file)
@@ -1 +1,2 @@
 # fss-0000
+_di_libcap_ Disable libcap support, allow for compiling and linking without libcap (-lcap).
index f58c5d8090a2a05f75fb183542b486beab374491..10b680a69f1a1fc060d1a286fa7da2b3f5cc160d 100644 (file)
@@ -5,6 +5,7 @@ f_status
 f_memory
 f_string
 f_utf
+f_capability
 f_color
 f_console
 f_directory
index 12603ca2e586bdc326c638bac968d167c9dc2a5b..185fb9312ea2600fdb0ae38e4118cdeb1df70bbc 100644 (file)
@@ -18,8 +18,8 @@ modes_default monolithic
 build_compiler gcc
 build_indexer ar
 build_language c
-build_libraries -lc
-build_libraries-individual -lfll_error -lfll_execute -lfll_fss -lfll_program -lfl_color -lfl_console -lfl_conversion -lfl_environment -lfl_fss -lfl_status -lfl_string -lf_console -lf_conversion -lf_directory -lf_environment -lf_file -lf_fss -lf_memory -lf_path -lf_pipe -lf_print -lf_signal -lf_utf
+build_libraries -lc -lcap
+build_libraries-individual -lfll_error -lfll_execute -lfll_fss -lfll_program -lfl_color -lfl_console -lfl_conversion -lfl_environment -lfl_fss -lfl_status -lfl_string -lf_capability -lf_console -lf_conversion -lf_directory -lf_environment -lf_file -lf_fss -lf_memory -lf_path -lf_pipe -lf_print -lf_signal -lf_utf
 build_libraries-level -lfll_2 -lfll_1 -lfll_0
 build_libraries-monolithic -lfll
 build_sources_library firewall.c private-firewall.c
@@ -46,7 +46,7 @@ search_exclusive yes
 search_shared yes
 search_static yes
 
-defines_all -D_en_firewall_debug_
+defines_all
 defines_static
 defines_shared