This focuses primarily on getting control groups working.
There are also some f_account changes, but nothing in the control program used the f_account changes.
build_language c
build_libraries -lc -lcap
build_libraries-level
-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_library account.c private-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 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_headers account.h account-common.h capability.h capability-common.h color.h console.h console-common.h control_group.h control_group-common.h conversion.h conversion-common.h directory.h directory_type.h directory-common.h environment.h environment-common.h execute.h execute-common.h file.h file-common.h fss.h fss-common.h fss_comment.h fss_delimit.h fss_named.h fss_nest.h fss_quote.h fss_set.h iki.h iki-common.h 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
build_language c
build_libraries -lc
build_libraries-level -lfll_0
-build_sources_library color.c console.c conversion.c directory.c private-directory.c environment.c private-fss.c fss_basic.c fss_basic_list.c fss_embedded_list.c fss_extended.c fss_extended_list.c iki.c print.c private-print.c status.c string.c private-string.c type.c private-type.c utf.c private-utf.c utf_file.c private-utf_file.c
+build_sources_library color.c console.c control_group.c conversion.c directory.c private-directory.c environment.c private-fss.c fss_basic.c fss_basic_list.c fss_embedded_list.c fss_extended.c fss_extended_list.c iki.c print.c private-print.c status.c string.c private-string.c type.c private-type.c utf.c private-utf.c utf_file.c private-utf_file.c
build_sources_program
-build_sources_headers color.h console.h conversion.h directory.h environment.h execute.h execute-common.h fss.h fss_basic.h fss_basic_list.h fss_embedded_list.h fss_extended.h fss_extended_list.h fss_status.h iki.h print.h status.h string.h type.h utf.h utf_file.h
+build_sources_headers color.h console.h control_group.h conversion.h directory.h environment.h execute.h execute-common.h fss.h fss_basic.h fss_basic_list.h fss_embedded_list.h fss_extended.h fss_extended_list.h fss_status.h iki.h print.h status.h string.h type.h utf.h utf_file.h
build_sources_script
build_sources_setting
build_script yes
build_language c
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_library control_group.c 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
-build_sources_headers environment.h error.h error-common.h execute.h file.h fss.h fss_basic.h fss_basic_list.h fss_embedded_list.h fss_extended.h fss_extended_list.h fss_status.h iki.h path.h program.h status.h
+build_sources_headers control_group.h environment.h error.h error-common.h execute.h file.h fss.h fss_basic.h fss_basic_list.h fss_embedded_list.h fss_extended.h fss_extended_list.h fss_status.h iki.h path.h program.h status.h
build_sources_script
build_sources_setting
build_script yes
build_language c
build_libraries -lc -lcap
build_libraries-monolithic
-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_library level_0/account.c level_0/private-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/control_group.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/control_group.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/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_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/control_group.h level_0/control_group-common.h level_0/conversion.h level_0/conversion-common.h level_0/directory.h level_0/directory_type.h level_0/directory-common.h level_0/environment.h level_0/environment-common.h level_0/execute.h level_0/execute-common.h level_0/file.h level_0/file-common.h level_0/fss.h level_0/fss-common.h level_0/fss_comment.h level_0/fss_delimit.h level_0/fss_named.h level_0/fss_nest.h level_0/fss_quote.h level_0/fss_set.h level_0/iki.h level_0/iki-common.h level_0/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/control_group.h level_1/conversion.h level_1/directory.h level_1/environment.h level_1/execute.h level_1/execute-common.h level_1/fss.h level_1/fss_basic.h level_1/fss_basic_list.h level_1/fss_embedded_list.h level_1/fss_extended.h level_1/fss_extended_list.h level_1/fss_status.h level_1/iki.h level_1/print.h level_1/status.h level_1/string.h level_1/type.h level_1/utf.h level_1/utf_file.h level_2/control_group.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
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_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
+ for i in f_type f_status f_memory f_string f_utf f_account f_capability f_color f_console f_control_group 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_control_group 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_control_group 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/ &&
#define f_account_pwd_length_fallback_second 32767
#endif // _di_f_account_defines_
+/**
+ * Provide a complete standard password account structure.
+ *
+ * id_user: The user ID.
+ * id_group: The group ID.
+ * home: The user's home directory.
+ * label: The user's display name (gecos).
+ * name: The user's account name.
+ * password: The user's password.
+ * shell: The user's shell program.
+ */
+#ifndef _di_f_account_t_
+ typedef struct {
+ uid_t id_user;
+ gid_t id_group;
+
+ f_string_dynamic_t home;
+ f_string_dynamic_t label;
+ f_string_dynamic_t name;
+ f_string_dynamic_t password;
+ f_string_dynamic_t shell;
+ } f_account_t;
+
+ #define f_account_t_initialize { 0, 0, f_string_dynamic_t_initialize, f_string_dynamic_t_initialize, f_string_dynamic_t_initialize, f_string_dynamic_t_initialize, f_string_dynamic_t_initialize }
+
+ #define f_macro_account_t_clear(account) \
+ account.id_user = 0; \
+ account.id_group = 0; \
+ f_macro_account_t_clear(account.home); \
+ f_macro_account_t_clear(account.label); \
+ f_macro_account_t_clear(account.name); \
+ f_macro_account_t_clear(account.password); \
+ f_macro_account_t_clear(account.shell);
+
+ #define f_macro_account_t_delete(status, account) \
+ f_macro_string_dynamic_t_delete(status, account.home); \
+ if (F_status_is_error_not(status)) f_macro_string_dynamic_t_delete(status, account.label); \
+ if (F_status_is_error_not(status)) f_macro_string_dynamic_t_delete(status, account.name); \
+ if (F_status_is_error_not(status)) f_macro_string_dynamic_t_delete(status, account.password); \
+ if (F_status_is_error_not(status)) f_macro_string_dynamic_t_delete(status, account.shell);
+
+ #define f_macro_account_t_destroy(status, account) \
+ f_macro_string_dynamic_t_destroy(status, account.home); \
+ if (F_status_is_error_not(status)) f_macro_string_dynamic_t_destroy(status, account.label); \
+ if (F_status_is_error_not(status)) f_macro_string_dynamic_t_destroy(status, account.name); \
+ if (F_status_is_error_not(status)) f_macro_string_dynamic_t_destroy(status, account.password); \
+ if (F_status_is_error_not(status)) f_macro_string_dynamic_t_destroy(status, account.shell);
+
+ #define f_macro_account_t_delete_simple(account) \
+ f_macro_string_dynamic_t_delete_simple(account.home); \
+ f_macro_string_dynamic_t_delete_simple(account.label); \
+ f_macro_string_dynamic_t_delete_simple(account.name); \
+ f_macro_string_dynamic_t_delete_simple(account.password); \
+ f_macro_string_dynamic_t_delete_simple(account.shell);
+
+ #define f_macro_account_t_destroy_simple(account) \
+ f_macro_string_dynamic_t_destroy_simple(account.home); \
+ f_macro_string_dynamic_t_destroy_simple(account.label); \
+ f_macro_string_dynamic_t_destroy_simple(account.name); \
+ f_macro_string_dynamic_t_destroy_simple(account.password); \
+ f_macro_string_dynamic_t_destroy_simple(account.shell);
+#endif // _di_f_account_t_
+
+/**
+ * An array of accounts.
+ *
+ * array: the array of accounts.
+ * size: total amount of space available.
+ * used: total number of space used.
+ */
+#ifndef _di_f_accounts_t_
+ typedef struct {
+ f_account_t *array;
+
+ f_array_length_t size;
+ f_array_length_t used;
+ } f_accounts_t;
+
+ #define f_accounts_t_initialize { 0, 0, 0 }
+
+ #define f_macro_accounts_t_clear(accounts) \
+ accounts.array = 0; \
+ accounts.size = 0; \
+ accounts.used = 0;
+
+ #define f_macro_accounts_new(status, accounts, length) \
+ f_macro_accounts_clear(accounts) \
+ status = f_memory_new((void **) & accounts.array, sizeof(f_account_t), length); \
+ if (status == F_none) { \
+ accounts.size = length; \
+ accounts.used = 0; \
+ }
+
+ #define f_macro_string_accounts_t_delete(status, accounts) \
+ status = F_none; \
+ accounts.used = accounts.size; \
+ while (accounts.used) { \
+ accounts.used--; \
+ f_macro_account_t_delete(status, accounts.array[accounts.used]); \
+ if (status != F_none) break; \
+ } \
+ if (status == F_none) status = f_memory_delete((void **) & accounts.array, sizeof(f_account_t), accounts.size); \
+ if (status == F_none) accounts.size = 0;
+
+ #define f_macro_string_accounts_t_destroy(status, accounts) \
+ status = F_none; \
+ accounts.used = accounts.size; \
+ while (accounts.used) { \
+ accounts.used--; \
+ f_macro_account_t_destroy(status, accounts.array[accounts.used]); \
+ if (status != F_none) break; \
+ } \
+ if (status == F_none) status = f_memory_destroy((void **) & accounts.array, sizeof(f_account_t), accounts.size); \
+ if (status == F_none) accounts.size = 0;
+
+ #define f_macro_string_accounts_t_delete_simple(accounts) \
+ accounts.used = accounts.size; \
+ while (accounts.used) { \
+ accounts.used--; \
+ f_macro_account_t_delete_simple(accounts.array[accounts.used]); \
+ } \
+ f_memory_delete((void **) & accounts.array, sizeof(f_account_t), accounts.size); \
+ accounts.size = 0;
+
+ #define f_macro_string_accounts_t_destroy_simple(accounts) \
+ accounts.used = accounts.size; \
+ while (accounts.used > 0) { \
+ accounts.used--; \
+ f_macro_account_t_destroy_simple(accounts.array[accounts.used]); \
+ } \
+ f_memory_destroy((void **) & accounts.array, sizeof(f_account_t), accounts.size); \
+ accounts.size = 0;
+
+ #define f_macro_string_accounts_t_resize(status, accounts, new_length) \
+ status = F_none; \
+ if (new_length < accounts.size) { \
+ for (f_array_length_t _macro__i = accounts.size - new_length; _macro__i < accounts.size; _macro__i++) { \
+ f_macro_account_t_delete(status, accounts.array[_macro__i]); \
+ if (status != F_none) break; \
+ } \
+ } \
+ if (status == F_none) status = f_memory_resize((void **) & accounts.array, sizeof(f_account_t), accounts.size, new_length); \
+ if (status == F_none) { \
+ if (new_length > accounts.size) { \
+ for (f_array_length_t _macro__i = accounts.size; _macro__i < new_length; _macro__i++) { \
+ memset(&accounts.array[_macro__i], 0, sizeof(f_account_t)); \
+ } \
+ } \
+ accounts.size = new_length; \
+ if (accounts.used > accounts.size) accounts.used = new_length; \
+ }
+
+ #define f_macro_string_accounts_t_adjust(status, accounts, new_length) \
+ status = F_none; \
+ if (new_length < accounts.size) { \
+ for (f_array_length_t _macro__i = accounts.size - new_length; _macro__i < accounts.size; _macro__i++) { \
+ f_macro_account_t_destroy(status, accounts.array[_macro__i], f_account_t); \
+ if (status != F_none) break; \
+ } \
+ } \
+ if (status == F_none) status = f_memory_adjust((void **) & accounts.array, sizeof(f_account_t), accounts.size, new_length); \
+ if (status == F_none) { \
+ if (new_length > accounts.size) { \
+ for (f_array_length_t _macro__i = accounts.size; _macro__i < new_length; _macro__i++) { \
+ memset(&accounts.array[_macro__i], 0, sizeof(f_account_t)); \
+ } \
+ } \
+ accounts.size = new_length; \
+ if (accounts.used > accounts.size) accounts.used = new_length; \
+ }
+#endif // _di_f_accounts_t_
+
#ifdef __cplusplus
} // extern "C"
#endif
#include "account.h"
+#include "private-account.h"
#ifdef __cplusplus
extern "C" {
#endif
+#ifndef _di_f_account_by_name_
+ f_return_status f_account_by_name(const f_string_t name, f_account_t *account) {
+ #ifndef _di_level_0_parameter_checking_
+ if (!account) return F_status_set_error(F_parameter);
+ #endif // _di_level_0_parameter_checking_
+
+ account->id_user = 0;
+ account->id_group = 0;
+ account->home.used = 0;
+ account->label.used = 0;
+ account->name.used = 0;
+ account->password.used = 0;
+ account->shell.used = 0;
+
+ 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 = 0;
+
+ size_t length = length_max;
+
+ {
+ if (length == -1) {
+ length = f_account_pwd_length_fallback_first;
+ }
+
+ // must be set to 0 to avoid problems due to the design of getpwnam()/getpwnam_r().
+ errno = 0;
+
+ char buffer[length];
+ const int result = getpwnam_r(name, &password, buffer, length, &pointer);
+
+ if (result) {
+ if (errno == EINTR) return F_status_set_error(F_interrupt);
+ if (errno == EIO) return F_status_set_error(F_input_output);
+ if (errno == EMFILE) return F_status_set_error(F_file_descriptor_max);
+ if (errno == ENFILE) return F_status_set_error(F_file_open_max);
+ if (errno == ENOMEM) return F_status_set_error(F_memory_not);
+
+ if (errno == ERANGE) {
+ if (length_max > 0) return F_status_set_error(F_buffer_too_small);
+ }
+ else {
+ return F_status_set_error(F_failure);
+ }
+ }
+ else {
+ if (!pointer) {
+ return F_exist_not;
+ }
+
+ return private_f_account_from_passwd(password, length, account);
+ }
+ }
+
+ length = f_account_pwd_length_fallback_second;
+
+ char buffer[f_account_pwd_length_fallback_second];
+
+ const int result = getpwnam_r(name, &password, buffer, length, &pointer);
+
+ if (result) {
+ if (errno == EINTR) return F_status_set_error(F_interrupt);
+ if (errno == EIO) return F_status_set_error(F_input_output);
+ if (errno == EMFILE) return F_status_set_error(F_file_descriptor_max);
+ if (errno == ENFILE) return F_status_set_error(F_file_open_max);
+ if (errno == ENOMEM) return F_status_set_error(F_memory_not);
+ if (errno == ERANGE) return F_status_set_error(F_buffer_too_small);
+
+ return F_status_set_error(F_failure);
+ }
+
+ if (!pointer) {
+ return F_exist_not;
+ }
+
+ return private_f_account_from_passwd(password, length, account);
+ }
+#endif // _di_f_account_by_name_
+
+#ifndef _di_f_account_by_id_
+ f_return_status f_account_by_id(const uid_t id, f_account_t *account) {
+ #ifndef _di_level_0_parameter_checking_
+ if (!account) return F_status_set_error(F_parameter);
+ #endif // _di_level_0_parameter_checking_
+
+ account->id_user = 0;
+ account->id_group = 0;
+ account->home.used = 0;
+ account->label.used = 0;
+ account->name.used = 0;
+ account->password.used = 0;
+ account->shell.used = 0;
+
+ 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 = 0;
+
+ size_t length = length_max;
+
+ {
+ if (length == -1) {
+ length = f_account_pwd_length_fallback_first;
+ }
+
+ // must be set to 0 to avoid problems due to the design of getpwuid()/getpwuid_r().
+ errno = 0;
+
+ char buffer[length];
+ const int result = getpwuid_r(id, &password, buffer, length, &pointer);
+
+ if (result) {
+ if (errno == EINTR) return F_status_set_error(F_interrupt);
+ if (errno == EIO) return F_status_set_error(F_input_output);
+ if (errno == EMFILE) return F_status_set_error(F_file_descriptor_max);
+ if (errno == ENFILE) return F_status_set_error(F_file_open_max);
+ if (errno == ENOMEM) return F_status_set_error(F_memory_not);
+
+ if (errno == ERANGE) {
+ if (length_max > 0) return F_status_set_error(F_buffer_too_small);
+ }
+ else {
+ return F_status_set_error(F_failure);
+ }
+ }
+ else {
+ if (!pointer) {
+ return F_exist_not;
+ }
+
+ return private_f_account_from_passwd(password, length, account);
+ }
+ }
+
+ length = f_account_pwd_length_fallback_second;
+
+ char buffer[f_account_pwd_length_fallback_second];
+
+ const int result = getpwuid_r(id, &password, buffer, length, &pointer);
+
+ if (result) {
+ if (errno == EINTR) return F_status_set_error(F_interrupt);
+ if (errno == EIO) return F_status_set_error(F_input_output);
+ if (errno == EMFILE) return F_status_set_error(F_file_descriptor_max);
+ if (errno == ENFILE) return F_status_set_error(F_file_open_max);
+ if (errno == ENOMEM) return F_status_set_error(F_memory_not);
+ if (errno == ERANGE) return F_status_set_error(F_buffer_too_small);
+
+ return F_status_set_error(F_failure);
+ }
+
+ if (!pointer) {
+ return F_exist_not;
+ }
+
+ return private_f_account_from_passwd(password, length, account);
+ }
+#endif // _di_f_account_by_id_
+
#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_
}
#endif // _di_f_account_id_user_by_name_
+#ifndef _di_f_account_name_user_by_id_
+ f_return_status f_account_name_user_by_id(const uid_t id, 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_
+
+ name->used = 0;
+
+ 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 = 0;
+
+ size_t length = length_max + 1;
+
+ {
+ if (length == -1) {
+ length = f_account_pwd_length_fallback_first;
+ }
+
+ // must be set to 0 to avoid problems due to the design of getpwuid()/getpwuid_r().
+ errno = 0;
+
+ char buffer[length];
+ const int result = getpwuid_r(id, &password, buffer, length, &pointer);
+
+ if (result) {
+ if (errno == EINTR) return F_status_set_error(F_interrupt);
+ if (errno == EIO) return F_status_set_error(F_input_output);
+ if (errno == EMFILE) return F_status_set_error(F_file_descriptor_max);
+ if (errno == ENFILE) return F_status_set_error(F_file_open_max);
+ if (errno == ENOMEM) return F_status_set_error(F_memory_not);
+
+ if (errno == ERANGE) {
+ if (length_max > 0) return F_status_set_error(F_buffer_too_small);
+ }
+ else {
+ return F_status_set_error(F_failure);
+ }
+ }
+ else {
+ if (!pointer) {
+ return F_exist_not;
+ }
+
+ const f_string_length_t name_length = strnlen(password.pw_name, length);
+
+ f_macro_string_dynamic_t_resize(status, (*name), name_length + 1);
+ if (F_status_is_error(status)) return status;
+
+ memcpy(name->string, password.pw_name, name_length);
+
+ name->string[name_length] = 0;
+ name->used = name_length;
+
+ return F_none;
+ }
+ }
+
+ length = f_account_pwd_length_fallback_second;
+
+ char buffer[f_account_pwd_length_fallback_second];
+
+ const int result = getpwuid_r(id, &password, buffer, length, &pointer);
+
+ if (result) {
+ if (errno == EINTR) return F_status_set_error(F_interrupt);
+ if (errno == EIO) return F_status_set_error(F_input_output);
+ if (errno == EMFILE) return F_status_set_error(F_file_descriptor_max);
+ if (errno == ENFILE) return F_status_set_error(F_file_open_max);
+ if (errno == ENOMEM) return F_status_set_error(F_memory_not);
+ if (errno == ERANGE) return F_status_set_error(F_buffer_too_small);
+
+ return F_status_set_error(F_failure);
+ }
+
+ if (!pointer) {
+ return F_exist_not;
+ }
+
+ const f_string_length_t name_length = strnlen(password.pw_name, length);
+
+ f_macro_string_dynamic_t_resize(status, (*name), name_length + 1);
+ if (F_status_is_error(status)) return status;
+
+ memcpy(name->string, password.pw_name, name_length);
+
+ name->string[name_length] = 0;
+ name->used = name_length;
+
+ return F_none;
+ }
+#endif // _di_f_account_name_user_by_id_
+
#ifdef __cplusplus
} // extern "C"
#endif
*
* Provides account related functionality (users, groups, roles, etc..).
*
- * @todo POSIX as of POSIX.1-2001, at least getpwnam() does not call "not found" an error.
- * For now, using getpwnam_r() in place of getpwnam() (and similar) seems the safest way to avoid this bad design.
+ * POSIX as of POSIX.1-2001, at least getpwnam() does not call "not found" an error.
+ * This uses getpwnam_r() in place of getpwnam() (and similar) as the safest way to avoid this bad design.
*/
#ifndef _F_account_h
#define _F_account_h
#endif
/**
+ * Get the user account by the user name.
+ *
+ * @param name
+ * The user name.
+ * The name must be NULL terminated.
+ * @param account
+ * This is replaced with by the account information.
+ * All strings will be NULL terminated.
+ *
+ * @return
+ * F_none on success.
+ * F_buffer_too_small (with error bit) if the buffer is too small to store the account data.
+ * F_exist_non if no user by that name exists.
+ * F_file_descriptor_max (with error bit) if max file descriptors was reached.
+ * F_file_open_max (with error bit) too many open files.
+ * F_input_output (with error bit) if an I/O error occurred.
+ * 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 error.
+ *
+ * @see getpwnam_r()
+ */
+#ifndef _di_f_account_by_name_
+ extern f_return_status f_account_by_name(const f_string_t name, f_account_t *account);
+#endif // _di_f_account_by_name_
+
+/**
+ * Get the user account by the user id.
+ *
+ * @param id
+ * The id of the user.
+ * @param account
+ * This is replaced with by the account information.
+ * All strings will be NULL terminated.
+ *
+ * @return
+ * F_none on success.
+ * F_buffer_too_small (with error bit) if the buffer is too small to store the account data.
+ * F_exist_non if no user by that name exists.
+ * F_file_descriptor_max (with error bit) if max file descriptors was reached.
+ * F_file_open_max (with error bit) too many open files.
+ * F_input_output (with error bit) if an I/O error occurred.
+ * 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 error.
+ *
+ * @see getpwuid_r()
+ */
+#ifndef _di_f_account_by_id_
+ extern f_return_status f_account_by_id(const uid_t id, f_account_t *account);
+#endif // _di_f_account_by_id_
+
+/**
* Get the group account id by the group name.
*
* @param name
extern f_return_status f_account_id_user_by_name(const f_string_t name, uid_t *id);
#endif // _di_f_account_id_user_by_name_
+/**
+ * Get the user account name by the user id.
+ *
+ * @param id
+ * The id of the user.
+ * @param name
+ * This is replaced with by the user name.
+ * The name will be NULL terminated.
+ *
+ * @return
+ * F_none on success.
+ * F_buffer_too_small (with error bit) if the buffer is too small to store the account data.
+ * F_exist_non if no user by that name exists.
+ * F_file_descriptor_max (with error bit) if max file descriptors was reached.
+ * F_file_open_max (with error bit) too many open files.
+ * F_input_output (with error bit) if an I/O error occurred.
+ * 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 error.
+ *
+ * @see getpwuid_r()
+ */
+#ifndef _di_f_account_name_user_by_id_
+ extern f_return_status f_account_name_user_by_id(const uid_t id, f_string_dynamic_t *name);
+#endif // _di_f_account_name_user_by_id_
+
#ifdef __cplusplus
} // extern "C"
#endif
--- /dev/null
+#include "account.h"
+#include "private-account.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if !defined(_di_f_account_by_name_) || !defined(_di_f_account_by_id_)
+ f_return_status private_f_account_from_passwd(const struct passwd password, const f_string_length_t password_length, f_account_t *account) {
+ f_status_t status = F_none;
+
+
+ // Account UID and GID.
+ account->id_user = password.pw_uid;
+ account->id_group = password.pw_gid;
+
+
+ // account home directory.
+ f_string_length_t string_length = strnlen(password.pw_dir, password_length);
+
+ f_macro_string_dynamic_t_resize(status, account->home, string_length + 1);
+ if (F_status_is_error(status)) return status;
+
+ memcpy(account->home.string, password.pw_dir, string_length);
+
+ account->home.string[string_length] = 0;
+ account->home.used = string_length;
+
+
+ // account label (gecos).
+ string_length = strnlen(password.pw_gecos, password_length);
+
+ f_macro_string_dynamic_t_resize(status, account->label, string_length + 1);
+ if (F_status_is_error(status)) return status;
+
+ memcpy(account->label.string, password.pw_gecos, string_length);
+
+ account->label.string[string_length] = 0;
+ account->label.used = string_length;
+
+
+ // account name.
+ string_length = strnlen(password.pw_name, password_length);
+
+ f_macro_string_dynamic_t_resize(status, account->name, string_length + 1);
+ if (F_status_is_error(status)) return status;
+
+ memcpy(account->name.string, password.pw_name, string_length);
+
+ account->name.string[string_length] = 0;
+ account->name.used = string_length;
+
+
+ // account password directory.
+ string_length = strnlen(password.pw_passwd, password_length);
+
+ f_macro_string_dynamic_t_resize(status, account->password, string_length + 1);
+ if (F_status_is_error(status)) return status;
+
+ memcpy(account->password.string, password.pw_passwd, string_length);
+
+ account->password.string[string_length] = 0;
+ account->password.used = string_length;
+
+
+ // account shell directory.
+ string_length = strnlen(password.pw_shell, password_length);
+
+ f_macro_string_dynamic_t_resize(status, account->shell, string_length + 1);
+ if (F_status_is_error(status)) return status;
+
+ memcpy(account->shell.string, password.pw_shell, string_length);
+
+ account->shell.string[string_length] = 0;
+ account->shell.used = string_length;
+
+ return F_none;
+ }
+#endif // !defined(_di_f_account_by_name_) || !defined(_di_f_account_by_id_)
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/**
+ * FLL - Level 0
+ *
+ * Project: Account
+ * API Version: 0.5
+ * Licenses: lgplv2.1
+ *
+ * These are provided for internal reduction in redundant code.
+ * These should not be exposed/used outside of this project.
+ */
+#ifndef _PRIVATE_F_account_h
+#define _PRIVATE_F_account_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Private helper for converting an entire "struct passwd" to a complete f_account_t.
+ *
+ * Intended to be shared to each of the different implementation variations.
+ *
+ * @param passwd
+ * The password structure.
+ * @param passwd_length
+ * The length of the password structure buffer.
+ * @param account
+ * This is replaced with by the account information.
+ * All strings will be NULL terminated.
+ * This assumes that all strings in account have their used set to the desired length, such as 0.
+ *
+ * @return
+ * F_none on success.
+ *
+ * Errors (with error bit) from f_macro_string_dynamic_t_resize().
+ *
+ * @see f_account_by_name()
+ * @see f_account_by_id()
+ * @see f_macro_string_dynamic_t_resize()
+ */
+#if !defined(_di_f_account_by_name_) || !defined(_di_f_account_by_id_)
+ extern f_return_status private_f_account_from_passwd(const struct passwd password, const f_string_length_t password_length, f_account_t *account) f_gcc_attribute_visibility_internal;
+#endif // !defined(_di_f_account_by_name_) || !defined(_di_f_account_by_id_)
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _PRIVATE_F_account_h
build_language c
build_libraries -lc
build_libraries-individual -lf_memory
-build_sources_library account.c
+build_sources_library account.c private-account.c
build_sources_program
build_sources_headers account.h account-common.h
build_sources_script
*
* 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.
+ * This is auto-included by capability.h and should not need to be explicitly included.
*/
#ifndef _F_capability_common_h
#define _F_capability_common_h
--- /dev/null
+/**
+ * FLL - Level 0
+ *
+ * Project: Control Group
+ * API Version: 0.5
+ * Licenses: lgplv2.1
+ *
+ * Defines common data to be used for/by control group (cgroup) related functionality.
+ *
+ * This is auto-included by control.h and should not need to be explicitly included.
+ */
+#ifndef _F_control_group_common_h
+#define _F_control_group_common_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * The defines for control groups.
+ */
+#ifndef _di_fl_control_group_defines_
+ #define f_control_group_path_system_default "sys/fs/cgroup/"
+ #define f_control_group_path_system_prefix "/"
+ #define f_control_group_path_system_suffix "/cgroup.procs"
+
+ #define f_control_group_path_system_default_length 14
+ #define f_control_group_path_system_prefix_length 1
+ #define f_control_group_path_system_suffix_length 13
+
+ #define f_control_group_pid_length_max 64
+
+ const static f_string_t f_control_group_path_system_default_s = f_control_group_path_system_default;
+ const static f_string_t f_control_group_path_system_prefix_s = f_control_group_path_system_prefix;
+ const static f_string_t f_control_group_path_system_suffix_s = f_control_group_path_system_suffix;
+#endif // _di_fl_control_group_defines_
+
+/**
+ * Provide a structure for associating some process with one or more control groups (cgroups).
+ *
+ * as_new: If TRUE then the control group is to be unshared, and FALSE the control group is not to be unshared.
+ * path: The sysfs path, must have the trailing slash (such as "/sys/fs/cgroup/").
+ * groups: An array of control groups, relative to the sysfs path (such as "memory/example").
+ */
+#ifndef _di_f_control_group_t_
+ typedef struct {
+ bool as_new;
+
+ f_string_dynamic_t path;
+ f_string_dynamics_t groups;
+ } f_control_group_t;
+
+ #define f_control_group_t_initialize { F_false, f_string_dynamic_t_initialize, f_string_dynamics_t_initialize }
+
+ #define f_macro_control_group_t_clear(control) \
+ control.as_new = F_false; \
+ f_macro_string_dynamic_t_clear(control.path); \
+ f_macro_string_dynamics_t_clear(control.groups);
+
+ #define f_macro_control_group_t_delete(status, control) \
+ f_macro_string_dynamic_t_delete(status, control.path); \
+ if (F_status_is_error_not(status)) f_macro_string_dynamics_t_delete(status, control.groups);
+
+ #define f_macro_control_group_t_destroy(status, control) \
+ f_macro_string_dynamic_t_destroy(status, control.path); \
+ if (F_status_is_error_not(status)) f_macro_string_dynamics_t_destroy(status, control.groups);
+
+ #define f_macro_control_group_t_delete_simple(control) \
+ f_macro_string_dynamic_t_delete_simple(control.path); \
+ f_macro_string_dynamics_t_delete_simple(control.groups);
+
+ #define f_macro_control_group_t_destroy_simple(control) \
+ f_macro_string_dynamic_t_destroy_simple(control.path); \
+ f_macro_string_dynamics_t_destroy_simple(control.groups);
+#endif // _di_f_control_group_t_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _F_control_group_common_h
--- /dev/null
+/**
+ * FLL - Level 1
+ *
+ * Project: Control Group
+ * API Version: 0.5
+ * Licenses: lgplv2.1
+ *
+ * Provides control group (cgroup) related functionality.
+ *
+ * It appears that the control group, as documented in the Linux kernel, is changed via the sysfs instead of system calls.
+ * If there are system calls to set the control group for a given process then this will need to be updated to utilize that.
+ * Until then, this is an implementation that helps facilitate writing to the sysfs filesystem for adding a process to a particular control group.
+ *
+ * This is intended to be used with Control Groups (cgroups) Version 2.
+ */
+#ifndef _F_control_group_h
+#define _F_control_group_h
+
+// libc includes
+
+// fll-0 includes
+#include <level_0/type.h>
+#include <level_0/status.h>
+#include <level_0/memory.h>
+#include <level_0/string.h>
+
+// fll-1 control includes
+#include <level_0/control_group-common.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _F_control_group_h
--- /dev/null
+# fss-0000
--- /dev/null
+# fss-0000
+
+f_type
+f_status
+f_memory
+f_string
--- /dev/null
+# fss-0001
+
+project_name f_control_group
+
+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
+build_libraries-individual -lf_memory
+build_sources_library
+build_sources_program
+build_sources_headers control_group.h control_group-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
+defines_static
+defines_shared
+
+flags_all -z now -g -fdiagnostics-color=always
+flags_shared
+flags_static
+flags_library -fPIC
+flags_program -fPIE
#define f_file_t_initialize { 0, -1, f_file_flag_read_only, f_file_default_read_size, f_file_default_write_size }
- #define f_macro_file_t_initialize(stream, id, flag) { stream, id, flag, f_file_default_read_size, f_file_default_write_size }
+ #define f_macro_file_t_initialize(stream, id, flag, read_size, write_size) { stream, id, flag, read_size, write_size }
+ #define f_macro_file_t_initialize2(stream, id, flag) { stream, id, flag, f_file_default_read_size, f_file_default_write_size }
#define f_macro_file_t_clear(file) \
file.stream = 0; \
F_connected_not,
F_container,
F_container_not,
+ F_control,
+ F_control_not,
+ F_control_group,
+ F_control_group_not,
F_critical,
F_critical_not,
F_deadlock,
#define f_string_dynamics_t_initialize f_string_statics_t_initialize
- #define f_macro_string_dynamics_clear(dynamics) f_macro_string_statics_t_clear(dynamics)
+ #define f_macro_string_dynamics_t_clear(dynamics) f_macro_string_statics_t_clear(dynamics)
#define f_macro_string_dynamics_new(status, dynamics, length) \
- f_macro_string_dynamics_clear(dynamics) \
+ f_macro_string_dynamics_t_clear(dynamics) \
status = f_memory_new((void **) & dynamics.array, sizeof(f_string_dynamic_t), length); \
if (status == F_none) { \
dynamics.size = length; \
#define f_macro_string_map_multi_t_clear(map) \
f_macro_string_dynamic_t_clear(map.name) \
- f_macro_string_dynamics_clear(map.value)
+ f_macro_string_dynamics_t_clear(map.value)
#define f_macro_string_map_multi_t_delete(status, map) \
f_macro_string_dynamic_t_delete(status, map.name) \
--- /dev/null
+#include "control_group.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_fl_control_group_apply_
+ f_return_status fl_control_group_apply(const f_control_group_t control_group, const pid_t id) {
+ #ifndef _di_level_1_parameter_checking_
+ if (!id) return F_status_set_error(F_parameter);
+ #endif // _di_level_1_parameter_checking_
+
+ if (control_group.as_new) {
+ if (unshare(CLONE_NEWCGROUP) < 0) {
+ if (errno == EINVAL) return F_status_set_error(F_parameter);
+ if (errno == ENOMEM) return F_status_set_error(F_memory_not);
+ if (errno == ENOSPC) return F_status_set_error(F_space_not);
+ if (errno == EPERM) return F_status_set_error(F_prohibited);
+
+ return F_status_set_error(F_failure);
+ }
+ }
+
+ f_file_t file = f_macro_file_t_initialize2(0, -1, f_file_flag_write_only);
+ f_status_t status = F_none;
+ f_string_length_t length = 0;
+
+ for (f_array_length_t i = 0; i < control_group.groups.used; ++i) {
+
+ if (!control_group.groups.array[i].used) continue;
+
+ length = control_group.path.used + control_group.groups.array[i].used + f_control_group_path_system_suffix_length;
+
+ char path[length + 1];
+
+ if (control_group.path.used) {
+ memcpy(path, control_group.path.string, control_group.path.used);
+ }
+
+ memcpy(path + control_group.path.used, control_group.groups.array[i].string, control_group.groups.array[i].used);
+ memcpy(path + control_group.path.used + f_control_group_path_system_default_length, f_control_group_path_system_suffix, f_control_group_path_system_suffix_length);
+
+ path[length] = 0;
+
+ status = f_file_stream_open(path, 0, &file);
+ if (F_status_is_error(status)) break;
+
+ fprintf(file.stream, "%llu", id);
+ fflush(file.stream);
+
+ f_file_stream_close(F_true, &file);
+ if (F_status_is_error(status)) break;
+ } // for
+
+ if (F_status_is_error(status)) {
+ return status;
+ }
+
+ return F_none;
+ }
+#endif // _di_fl_control_group_apply_
+
+#ifndef _di_fl_control_group_delete_
+ f_return_status fl_control_group_delete(f_control_group_t *control_group) {
+ f_status_t status = F_none;
+
+ f_macro_control_group_t_delete(status, (*control_group));
+
+ return status;
+ }
+#endif // _di_fl_control_group_delete_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/**
+ * FLL - Level 1
+ *
+ * Project: Control Group
+ * API Version: 0.5
+ * Licenses: lgplv2.1
+ *
+ * Provides control group (cgroup) related functionality.
+ *
+ * It appears that the control group, as documented in the Linux kernel, is changed via the sysfs instead of system calls.
+ * If there are system calls to set the control group for a given process then this will need to be updated to utilize that.
+ * Until then, this is an implementation that helps facilitate writing to the sysfs filesystem for adding a process to a particular control group.
+ *
+ * This is intended to be used with Control Groups (cgroups) Version 2.
+ */
+#ifndef _FL_control_group_h
+#define _FL_control_group_h
+
+// include pre-requirements
+#define _GNU_SOURCE
+
+// libc includes
+#include <sched.h>
+#include <stdio.h>
+#include <string.h>
+
+// fll-0 includes
+#include <level_0/type.h>
+#include <level_0/status.h>
+#include <level_0/memory.h>
+#include <level_0/string.h>
+#include <level_0/control_group.h>
+#include <level_0/file.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Apply the given control groups to the process represented by the PID.
+ *
+ * @param control
+ * The control group(s) to apply.
+ * @param id
+ * The PID of the process to apply the control group(s) to.
+ *
+ * @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 the current user/process has insufficient privileges to set certain cgroup settings.
+ * F_space_not (with error bit) if a maximum resource limit is reached and there is not enough space.
+ * F_failure (with error bit) on any other error.
+ *
+ * Errors (with error bit) from: f_file_stream_open().
+ *
+ * @see fprintf()
+ * @see fflush()
+ * @see memcpy()
+ * @see unshare()
+ *
+ * @see f_file_stream_close()
+ * @see f_file_stream_open()
+ */
+#ifndef _di_fl_control_group_apply_
+ extern f_return_status fl_control_group_apply(const f_control_group_t control_group, const pid_t id);
+#endif // _di_fl_control_group_apply_
+
+/**
+ * Delete the control group structure.
+ *
+ * @param control_group
+ * The control group to delete.
+ *
+ * @return
+ * F_none on success.
+ * F_parameter (with error bit) if a parameter is invalid.
+ */
+#ifndef _di_fl_control_group_delete_
+ extern f_return_status fl_control_group_delete(f_control_group_t *control_group);
+#endif // _di_fl_control_group_delete_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _FL_control_group_h
--- /dev/null
+# fss-0000
--- /dev/null
+# fss-0000
+
+f_type
+f_status
+f_memory
+f_string
+f_control_group
+f_file
--- /dev/null
+# fss-0001
+
+project_name fl_control_group
+
+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
+build_libraries-individual -lf_file -lf_memory
+build_sources_library control_group.c
+build_sources_program
+build_sources_headers control_group.h
+build_sources_script
+build_sources_setting
+build_script yes
+build_shared yes
+build_static yes
+
+path_headers level_1
+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
+defines_static
+defines_shared
+
+flags_all -z now -g -fdiagnostics-color=always
+flags_shared
+flags_static
+flags_library -fPIC
+flags_program -fPIE
f_directory_statuss_t *failures;
} fl_directory_recurse_t;
- #define fl_directory_recurse_t_initialize { fl_directory_recurse_depth_max, f_file_default_read_size, F_false, f_macro_file_t_initialize(f_type_output, f_type_descriptor_output, f_file_flag_write_only), 0, 0 }
+ #define fl_directory_recurse_t_initialize { fl_directory_recurse_depth_max, f_file_default_read_size, F_false, f_macro_file_t_initialize2(f_type_output, f_type_descriptor_output, f_file_flag_write_only), 0, 0 }
#endif // _di_fl_directory_recurse_t_
/**
* 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 (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.
- * controls: an array of cgroups (control groups) to assign the child PID to, set to 0 to not use.
+ * 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 (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.
+ * control_group: 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 {
f_int32s_t *id_groups;
fl_execute_scheduler_t *scheduler;
- f_string_dynamics_t *controls;
+ f_control_group_t *control_group;
} fl_execute_as_t;
#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, controls) { nice, id_user, id_group, capability, id_groups, scheduler, controls }
+ #define fl_macro_execute_as_t_initialize(nice, id_user, id_group, capability, id_groups, scheduler, control_group) { nice, id_user, id_group, capability, id_groups, scheduler, control_group }
#define fl_execute_as_t_clear(as) \
as.nice = 0; \
as.capability = 0; \
as.id_groups = 0; \
as.scheduler = 0; \
- as.controls = 0;
+ as.control_group = 0;
#endif // _di_fl_execute_as_t_
#ifdef __cplusplus
#ifndef _FL_execute_h
#define _FL_execute_h
+// include pre-requirements
+#define _GNU_SOURCE
+
// libc includes
#include <grp.h>
#include <sched.h>
build_shared yes
build_static yes
-path_headers level_0
+path_headers level_1
path_headers_preserve no
path_library_script script
path_library_shared shared
case F_container_not:
*string = FL_status_string_container_not;
break;
+ case F_control:
+ *string = FL_status_string_control;
+ break;
+ case F_control_not:
+ *string = FL_status_string_control_not;
+ break;
+ case F_control_group:
+ *string = FL_status_string_control_group;
+ break;
+ case F_control_group_not:
+ *string = FL_status_string_control_group_not;
+ break;
case F_critical:
*string = FL_status_string_critical;
break;
#endif // _di_F_status_signal_
#ifndef _di_F_status_basic_
- #define FL_status_string_none "F_none"
- #define FL_status_string_absolute "F_absolute"
- #define FL_status_string_absolute_not "F_absolute_not"
- #define FL_status_string_address "F_address"
- #define FL_status_string_address_not "F_address_not"
- #define FL_status_string_block "F_block"
- #define FL_status_string_block_not "F_block_not"
- #define FL_status_string_bound "F_bound"
- #define FL_status_string_bound_not "F_bound_not"
- #define FL_status_string_capability "F_capability"
- #define FL_status_string_capability_not "F_capability_not"
- #define FL_status_string_child "F_child"
- #define FL_status_string_child_not "F_child_not"
- #define FL_status_string_complete "F_complete"
- #define FL_status_string_complete_not "F_complete_not"
- #define FL_status_string_connected "F_connected"
- #define FL_status_string_connected_not "F_connected_not"
- #define FL_status_string_container "F_container"
- #define FL_status_string_container_not "F_container_not"
- #define FL_status_string_critical "F_critical"
- #define FL_status_string_critical_not "F_critical_not"
- #define FL_status_string_deadlock "F_deadlock"
- #define FL_status_string_deadlock_not "F_deadlock_not"
- #define FL_status_string_descriptor "F_descriptor"
- #define FL_status_string_descriptor_not "F_descriptor_not"
- #define FL_status_string_device "F_device"
- #define FL_status_string_device_not "F_device_not"
- #define FL_status_string_dummy "F_dummy"
- #define FL_status_string_dummy_not "F_dummy_not"
- #define FL_status_string_encoding "F_encoding"
- #define FL_status_string_encoding_not "F_encoding_not"
- #define FL_status_string_eof "F_eof"
- #define FL_status_string_eof_not "F_eof_not"
- #define FL_status_string_eol "F_eol"
- #define FL_status_string_eol_not "F_eol_not"
- #define FL_status_string_eos "F_eos"
- #define FL_status_string_eos_not "F_eos_not"
- #define FL_status_string_exist "F_exist"
- #define FL_status_string_exist_not "F_exist_not"
- #define FL_status_string_failure "F_failure"
- #define FL_status_string_failure_not "F_failure_not"
- #define FL_status_string_fork "F_fork"
- #define FL_status_string_fork_not "F_fork_not"
- #define FL_status_string_found "F_found"
- #define FL_status_string_found_not "F_found_not"
- #define FL_status_string_group "F_group"
- #define FL_status_string_group_not "F_group_not"
- #define FL_status_string_ignore "F_ignore"
- #define FL_status_string_ignore_not "F_ignore_not"
- #define FL_status_string_input "F_input"
- #define FL_status_string_input_not "F_input_not"
- #define FL_status_string_input_output "F_input_output"
- #define FL_status_string_interrupt "F_interrupt"
- #define FL_status_string_interrupt_not "F_interrupt_not"
- #define FL_status_string_known "F_known"
- #define FL_status_string_known_not "F_known_not"
- #define FL_status_string_link "F_link"
- #define FL_status_string_link_not "F_link_not"
- #define FL_status_string_lock "F_lock"
- #define FL_status_string_lock_not "F_lock_not"
- #define FL_status_string_loop "F_loop"
- #define FL_status_string_loop_not "F_loop_not"
- #define FL_status_string_maybe "F_maybe"
- #define FL_status_string_maybe_not "F_maybe_not"
- #define FL_status_string_minor "F_minor"
- #define FL_status_string_minor_not "F_minor_not"
- #define FL_status_string_moderate "F_moderate"
- #define FL_status_string_moderate_not "F_moderate_not"
- #define FL_status_string_mount "F_mount"
- #define FL_status_string_mount_not "F_mount_not"
- #define FL_status_string_name "F_name"
- #define FL_status_string_name_not "F_name_not"
- #define FL_status_string_nice "F_nice"
- #define FL_status_string_nice_not "F_nice_not"
- #define FL_status_string_optional "F_optional"
- #define FL_status_string_optional_not "F_optional_not"
- #define FL_status_string_output "F_output"
- #define FL_status_string_output_not "F_output_not"
- #define FL_status_string_parameter "F_parameter"
- #define FL_status_string_parameter_not "F_parameter_not"
- #define FL_status_string_parent "F_parent"
- #define FL_status_string_parent_not "F_parent_not"
- #define FL_status_string_pipe "F_pipe"
- #define FL_status_string_pipe_not "F_pipe_not"
- #define FL_status_string_port "F_port"
- #define FL_status_string_port_not "F_port_not"
- #define FL_status_string_prohibited "F_prohibited"
- #define FL_status_string_prohibited_not "F_prohibited_not"
- #define FL_status_string_range "F_range"
- #define FL_status_string_range_not "F_range_not"
- #define FL_status_string_read "F_read"
- #define FL_status_string_read_not "F_read_not"
- #define FL_status_string_read_only "F_read_only"
- #define FL_status_string_ready "F_ready"
- #define FL_status_string_ready_not "F_ready_not"
- #define FL_status_string_recurse "F_recurse"
- #define FL_status_string_recurse_not "F_recurse_not"
- #define FL_status_string_relative "F_relative"
- #define FL_status_string_relative_not "F_relative_not"
- #define FL_status_string_require "F_require"
- #define FL_status_string_require_not "F_require_not"
- #define FL_status_string_resource "F_resource"
- #define FL_status_string_resource_not "F_resource_not"
- #define FL_status_string_search "F_search"
- #define FL_status_string_search_not "F_search_not"
- #define FL_status_string_schedule "F_schedule"
- #define FL_status_string_schedule_not "F_schedule_not"
- #define FL_status_string_signal "F_signal"
- #define FL_status_string_signal_not "F_signal_not"
- #define FL_status_string_space "F_space"
- #define FL_status_string_space_not "F_space_not"
- #define FL_status_string_stop "F_stop"
- #define FL_status_string_stop_not "F_stop_not"
- #define FL_status_string_string "F_string"
- #define FL_status_string_string_not "F_string_not"
- #define FL_status_string_string_too_large "F_string_too_large"
- #define FL_status_string_string_too_small "F_string_too_small"
- #define FL_status_string_syntax "F_syntax"
- #define FL_status_string_syntax_not "F_syntax_not"
- #define FL_status_string_supported "F_supported"
- #define FL_status_string_supported_not "F_supported_not"
- #define FL_status_string_user "F_user"
- #define FL_status_string_user_not "F_user_not"
- #define FL_status_string_utf "F_utf"
- #define FL_status_string_utf_not "F_utf_not"
- #define FL_status_string_valid "F_valid"
- #define FL_status_string_valid_not "F_valid_not"
- #define FL_status_string_value "F_value"
- #define FL_status_string_value_not "F_value_not"
- #define FL_status_string_wait "F_wait"
- #define FL_status_string_wait_not "F_wait_not"
- #define FL_status_string_warn "F_warn"
- #define FL_status_string_warn_not "F_warn_not"
- #define FL_status_string_world "F_world"
- #define FL_status_string_world_not "F_world_not"
- #define FL_status_string_write "F_write"
- #define FL_status_string_write_not "F_write_not"
- #define FL_status_string_write_only "F_write_only"
-
- #define FL_status_string_none_length 6
- #define FL_status_string_absolute_length 10
- #define FL_status_string_absolute_not_length 14
- #define FL_status_string_address_length 9
- #define FL_status_string_address_not_length 13
- #define FL_status_string_block_length 7
- #define FL_status_string_block_not_length 11
- #define FL_status_string_bound_length 7
- #define FL_status_string_bound_not_length 11
- #define FL_status_string_capability_length 12
- #define FL_status_string_capability_not_length 16
- #define FL_status_string_child_length 7
- #define FL_status_string_child_not_length 11
- #define FL_status_string_complete_length 10
- #define FL_status_string_complete_not_length 14
- #define FL_status_string_connected_length 11
- #define FL_status_string_connected_not_length 15
- #define FL_status_string_container_length 11
- #define FL_status_string_container_not_length 15
- #define FL_status_string_critical_length 10
- #define FL_status_string_critical_not_length 14
- #define FL_status_string_deadlock_length 10
- #define FL_status_string_deadlock_not_length 14
- #define FL_status_string_descriptor_length 12
- #define FL_status_string_descriptor_not_length 16
- #define FL_status_string_device_length 8
- #define FL_status_string_device_not_length 12
- #define FL_status_string_dummy_length 7
- #define FL_status_string_dummy_not_length 11
- #define FL_status_string_encoding_length 10
- #define FL_status_string_encoding_not_length 14
- #define FL_status_string_eof_length 5
- #define FL_status_string_eof_not_length 9
- #define FL_status_string_eol_length 5
- #define FL_status_string_eol_not_length 9
- #define FL_status_string_eos_length 5
- #define FL_status_string_eos_not_length 9
- #define FL_status_string_exist_length 7
- #define FL_status_string_exist_not_length 11
- #define FL_status_string_failure_length 9
- #define FL_status_string_failure_not_length 13
- #define FL_status_string_fork_length 6
- #define FL_status_string_fork_not_length 10
- #define FL_status_string_found_length 7
- #define FL_status_string_found_not_length 11
- #define FL_status_string_group_length 7
- #define FL_status_string_group_not_length 11
- #define FL_status_string_ignore_length 8
- #define FL_status_string_ignore_not_length 12
- #define FL_status_string_input_length 7
- #define FL_status_string_input_not_length 11
- #define FL_status_string_input_output_length 14
- #define FL_status_string_interrupt_length 11
- #define FL_status_string_interrupt_not_length 15
- #define FL_status_string_known_length 7
- #define FL_status_string_known_not_length 11
- #define FL_status_string_link_length 6
- #define FL_status_string_link_not_length 10
- #define FL_status_string_lock_length 6
- #define FL_status_string_lock_not_length 10
- #define FL_status_string_loop_length 6
- #define FL_status_string_loop_not_length 10
- #define FL_status_string_maybe_length 7
- #define FL_status_string_maybe_not_length 11
- #define FL_status_string_minor_length 7
- #define FL_status_string_minor_not_length 11
- #define FL_status_string_moderate_length 10
- #define FL_status_string_moderate_not_length 14
- #define FL_status_string_mount_length 7
- #define FL_status_string_mount_not_length 11
- #define FL_status_string_name_length 6
- #define FL_status_string_name_not_length 10
- #define FL_status_string_nice_length 6
- #define FL_status_string_nice_not_length 10
- #define FL_status_string_optional_length 10
- #define FL_status_string_optional_not_length 14
- #define FL_status_string_output_length 8
- #define FL_status_string_output_not_length 12
- #define FL_status_string_parameter_length 11
- #define FL_status_string_parameter_not_length 15
- #define FL_status_string_parent_length 8
- #define FL_status_string_parent_not_length 12
- #define FL_status_string_pipe_length 6
- #define FL_status_string_pipe_not_length 10
- #define FL_status_string_port_length 6
- #define FL_status_string_port_not_length 10
- #define FL_status_string_prohibited_length 12
- #define FL_status_string_prohibited_not_length 16
- #define FL_status_string_range_length 7
- #define FL_status_string_range_not_length 11
- #define FL_status_string_read_length 6
- #define FL_status_string_read_not_length 10
- #define FL_status_string_read_only_length 11
- #define FL_status_string_ready_length 7
- #define FL_status_string_ready_not_length 11
- #define FL_status_string_recurse_length 9
- #define FL_status_string_recurse_not_length 13
- #define FL_status_string_relative_length 10
- #define FL_status_string_relative_not_length 14
- #define FL_status_string_require_length 9
- #define FL_status_string_require_not_length 13
- #define FL_status_string_resource_length 10
- #define FL_status_string_resource_not_length 14
- #define FL_status_string_search_length 8
- #define FL_status_string_search_not_length 12
- #define FL_status_string_schedule_length 10
- #define FL_status_string_schedule_not_length 14
- #define FL_status_string_signal_length 8
- #define FL_status_string_signal_not_length 12
- #define FL_status_string_space_length 7
- #define FL_status_string_space_not_length 11
- #define FL_status_string_stop_length 6
- #define FL_status_string_stop_not_length 10
- #define FL_status_string_string_length 8
- #define FL_status_string_string_not_length 12
- #define FL_status_string_string_too_large_length 18
- #define FL_status_string_string_too_small_length 18
- #define FL_status_string_supported_length 11
- #define FL_status_string_supported_not_length 15
- #define FL_status_string_syntax_length 8
- #define FL_status_string_syntax_not_length 12
- #define FL_status_string_user_length 6
- #define FL_status_string_user_not_length 10
- #define FL_status_string_utf_length 5
- #define FL_status_string_utf_not_length 9
- #define FL_status_string_valid_length 7
- #define FL_status_string_valid_not_length 11
- #define FL_status_string_value_length 7
- #define FL_status_string_value_not_length 11
- #define FL_status_string_wait_length 6
- #define FL_status_string_wait_not_length 10
- #define FL_status_string_warn_length 6
- #define FL_status_string_warn_not_length 10
- #define FL_status_string_world_length 7
- #define FL_status_string_world_not_length 11
- #define FL_status_string_write_length 7
- #define FL_status_string_write_not_length 11
- #define FL_status_string_write_only_length 12
+ #define FL_status_string_none "F_none"
+ #define FL_status_string_absolute "F_absolute"
+ #define FL_status_string_absolute_not "F_absolute_not"
+ #define FL_status_string_address "F_address"
+ #define FL_status_string_address_not "F_address_not"
+ #define FL_status_string_block "F_block"
+ #define FL_status_string_block_not "F_block_not"
+ #define FL_status_string_bound "F_bound"
+ #define FL_status_string_bound_not "F_bound_not"
+ #define FL_status_string_capability "F_capability"
+ #define FL_status_string_capability_not "F_capability_not"
+ #define FL_status_string_child "F_child"
+ #define FL_status_string_child_not "F_child_not"
+ #define FL_status_string_complete "F_complete"
+ #define FL_status_string_complete_not "F_complete_not"
+ #define FL_status_string_connected "F_connected"
+ #define FL_status_string_connected_not "F_connected_not"
+ #define FL_status_string_container "F_container"
+ #define FL_status_string_container_not "F_container_not"
+ #define FL_status_string_control "F_control"
+ #define FL_status_string_control_not "F_control_not"
+ #define FL_status_string_control_group "F_control_group"
+ #define FL_status_string_control_group_not "F_control_group_not"
+ #define FL_status_string_critical "F_critical"
+ #define FL_status_string_critical_not "F_critical_not"
+ #define FL_status_string_deadlock "F_deadlock"
+ #define FL_status_string_deadlock_not "F_deadlock_not"
+ #define FL_status_string_descriptor "F_descriptor"
+ #define FL_status_string_descriptor_not "F_descriptor_not"
+ #define FL_status_string_device "F_device"
+ #define FL_status_string_device_not "F_device_not"
+ #define FL_status_string_dummy "F_dummy"
+ #define FL_status_string_dummy_not "F_dummy_not"
+ #define FL_status_string_encoding "F_encoding"
+ #define FL_status_string_encoding_not "F_encoding_not"
+ #define FL_status_string_eof "F_eof"
+ #define FL_status_string_eof_not "F_eof_not"
+ #define FL_status_string_eol "F_eol"
+ #define FL_status_string_eol_not "F_eol_not"
+ #define FL_status_string_eos "F_eos"
+ #define FL_status_string_eos_not "F_eos_not"
+ #define FL_status_string_exist "F_exist"
+ #define FL_status_string_exist_not "F_exist_not"
+ #define FL_status_string_failure "F_failure"
+ #define FL_status_string_failure_not "F_failure_not"
+ #define FL_status_string_fork "F_fork"
+ #define FL_status_string_fork_not "F_fork_not"
+ #define FL_status_string_found "F_found"
+ #define FL_status_string_found_not "F_found_not"
+ #define FL_status_string_group "F_group"
+ #define FL_status_string_group_not "F_group_not"
+ #define FL_status_string_ignore "F_ignore"
+ #define FL_status_string_ignore_not "F_ignore_not"
+ #define FL_status_string_input "F_input"
+ #define FL_status_string_input_not "F_input_not"
+ #define FL_status_string_input_output "F_input_output"
+ #define FL_status_string_interrupt "F_interrupt"
+ #define FL_status_string_interrupt_not "F_interrupt_not"
+ #define FL_status_string_known "F_known"
+ #define FL_status_string_known_not "F_known_not"
+ #define FL_status_string_link "F_link"
+ #define FL_status_string_link_not "F_link_not"
+ #define FL_status_string_lock "F_lock"
+ #define FL_status_string_lock_not "F_lock_not"
+ #define FL_status_string_loop "F_loop"
+ #define FL_status_string_loop_not "F_loop_not"
+ #define FL_status_string_maybe "F_maybe"
+ #define FL_status_string_maybe_not "F_maybe_not"
+ #define FL_status_string_minor "F_minor"
+ #define FL_status_string_minor_not "F_minor_not"
+ #define FL_status_string_moderate "F_moderate"
+ #define FL_status_string_moderate_not "F_moderate_not"
+ #define FL_status_string_mount "F_mount"
+ #define FL_status_string_mount_not "F_mount_not"
+ #define FL_status_string_name "F_name"
+ #define FL_status_string_name_not "F_name_not"
+ #define FL_status_string_nice "F_nice"
+ #define FL_status_string_nice_not "F_nice_not"
+ #define FL_status_string_optional "F_optional"
+ #define FL_status_string_optional_not "F_optional_not"
+ #define FL_status_string_output "F_output"
+ #define FL_status_string_output_not "F_output_not"
+ #define FL_status_string_parameter "F_parameter"
+ #define FL_status_string_parameter_not "F_parameter_not"
+ #define FL_status_string_parent "F_parent"
+ #define FL_status_string_parent_not "F_parent_not"
+ #define FL_status_string_pipe "F_pipe"
+ #define FL_status_string_pipe_not "F_pipe_not"
+ #define FL_status_string_port "F_port"
+ #define FL_status_string_port_not "F_port_not"
+ #define FL_status_string_prohibited "F_prohibited"
+ #define FL_status_string_prohibited_not "F_prohibited_not"
+ #define FL_status_string_range "F_range"
+ #define FL_status_string_range_not "F_range_not"
+ #define FL_status_string_read "F_read"
+ #define FL_status_string_read_not "F_read_not"
+ #define FL_status_string_read_only "F_read_only"
+ #define FL_status_string_ready "F_ready"
+ #define FL_status_string_ready_not "F_ready_not"
+ #define FL_status_string_recurse "F_recurse"
+ #define FL_status_string_recurse_not "F_recurse_not"
+ #define FL_status_string_relative "F_relative"
+ #define FL_status_string_relative_not "F_relative_not"
+ #define FL_status_string_require "F_require"
+ #define FL_status_string_require_not "F_require_not"
+ #define FL_status_string_resource "F_resource"
+ #define FL_status_string_resource_not "F_resource_not"
+ #define FL_status_string_search "F_search"
+ #define FL_status_string_search_not "F_search_not"
+ #define FL_status_string_schedule "F_schedule"
+ #define FL_status_string_schedule_not "F_schedule_not"
+ #define FL_status_string_signal "F_signal"
+ #define FL_status_string_signal_not "F_signal_not"
+ #define FL_status_string_space "F_space"
+ #define FL_status_string_space_not "F_space_not"
+ #define FL_status_string_stop "F_stop"
+ #define FL_status_string_stop_not "F_stop_not"
+ #define FL_status_string_string "F_string"
+ #define FL_status_string_string_not "F_string_not"
+ #define FL_status_string_string_too_large "F_string_too_large"
+ #define FL_status_string_string_too_small "F_string_too_small"
+ #define FL_status_string_syntax "F_syntax"
+ #define FL_status_string_syntax_not "F_syntax_not"
+ #define FL_status_string_supported "F_supported"
+ #define FL_status_string_supported_not "F_supported_not"
+ #define FL_status_string_user "F_user"
+ #define FL_status_string_user_not "F_user_not"
+ #define FL_status_string_utf "F_utf"
+ #define FL_status_string_utf_not "F_utf_not"
+ #define FL_status_string_valid "F_valid"
+ #define FL_status_string_valid_not "F_valid_not"
+ #define FL_status_string_value "F_value"
+ #define FL_status_string_value_not "F_value_not"
+ #define FL_status_string_wait "F_wait"
+ #define FL_status_string_wait_not "F_wait_not"
+ #define FL_status_string_warn "F_warn"
+ #define FL_status_string_warn_not "F_warn_not"
+ #define FL_status_string_world "F_world"
+ #define FL_status_string_world_not "F_world_not"
+ #define FL_status_string_write "F_write"
+ #define FL_status_string_write_not "F_write_not"
+ #define FL_status_string_write_only "F_write_only"
+
+ #define FL_status_string_none_length 6
+ #define FL_status_string_absolute_length 10
+ #define FL_status_string_absolute_not_length 14
+ #define FL_status_string_address_length 9
+ #define FL_status_string_address_not_length 13
+ #define FL_status_string_block_length 7
+ #define FL_status_string_block_not_length 11
+ #define FL_status_string_bound_length 7
+ #define FL_status_string_bound_not_length 11
+ #define FL_status_string_capability_length 12
+ #define FL_status_string_capability_not_length 16
+ #define FL_status_string_child_length 7
+ #define FL_status_string_child_not_length 11
+ #define FL_status_string_complete_length 10
+ #define FL_status_string_complete_not_length 14
+ #define FL_status_string_connected_length 11
+ #define FL_status_string_connected_not_length 15
+ #define FL_status_string_container_length 11
+ #define FL_status_string_container_not_length 15
+ #define FL_status_string_control_length 9
+ #define FL_status_string_control_not_length 13
+ #define FL_status_string_control_group_length 15
+ #define FL_status_string_control_group_not_length 19
+ #define FL_status_string_critical_length 10
+ #define FL_status_string_critical_not_length 14
+ #define FL_status_string_deadlock_length 10
+ #define FL_status_string_deadlock_not_length 14
+ #define FL_status_string_descriptor_length 12
+ #define FL_status_string_descriptor_not_length 16
+ #define FL_status_string_device_length 8
+ #define FL_status_string_device_not_length 12
+ #define FL_status_string_dummy_length 7
+ #define FL_status_string_dummy_not_length 11
+ #define FL_status_string_encoding_length 10
+ #define FL_status_string_encoding_not_length 14
+ #define FL_status_string_eof_length 5
+ #define FL_status_string_eof_not_length 9
+ #define FL_status_string_eol_length 5
+ #define FL_status_string_eol_not_length 9
+ #define FL_status_string_eos_length 5
+ #define FL_status_string_eos_not_length 9
+ #define FL_status_string_exist_length 7
+ #define FL_status_string_exist_not_length 11
+ #define FL_status_string_failure_length 9
+ #define FL_status_string_failure_not_length 13
+ #define FL_status_string_fork_length 6
+ #define FL_status_string_fork_not_length 10
+ #define FL_status_string_found_length 7
+ #define FL_status_string_found_not_length 11
+ #define FL_status_string_group_length 7
+ #define FL_status_string_group_not_length 11
+ #define FL_status_string_ignore_length 8
+ #define FL_status_string_ignore_not_length 12
+ #define FL_status_string_input_length 7
+ #define FL_status_string_input_not_length 11
+ #define FL_status_string_input_output_length 14
+ #define FL_status_string_interrupt_length 11
+ #define FL_status_string_interrupt_not_length 15
+ #define FL_status_string_known_length 7
+ #define FL_status_string_known_not_length 11
+ #define FL_status_string_link_length 6
+ #define FL_status_string_link_not_length 10
+ #define FL_status_string_lock_length 6
+ #define FL_status_string_lock_not_length 10
+ #define FL_status_string_loop_length 6
+ #define FL_status_string_loop_not_length 10
+ #define FL_status_string_maybe_length 7
+ #define FL_status_string_maybe_not_length 11
+ #define FL_status_string_minor_length 7
+ #define FL_status_string_minor_not_length 11
+ #define FL_status_string_moderate_length 10
+ #define FL_status_string_moderate_not_length 14
+ #define FL_status_string_mount_length 7
+ #define FL_status_string_mount_not_length 11
+ #define FL_status_string_name_length 6
+ #define FL_status_string_name_not_length 10
+ #define FL_status_string_nice_length 6
+ #define FL_status_string_nice_not_length 10
+ #define FL_status_string_optional_length 10
+ #define FL_status_string_optional_not_length 14
+ #define FL_status_string_output_length 8
+ #define FL_status_string_output_not_length 12
+ #define FL_status_string_parameter_length 11
+ #define FL_status_string_parameter_not_length 15
+ #define FL_status_string_parent_length 8
+ #define FL_status_string_parent_not_length 12
+ #define FL_status_string_pipe_length 6
+ #define FL_status_string_pipe_not_length 10
+ #define FL_status_string_port_length 6
+ #define FL_status_string_port_not_length 10
+ #define FL_status_string_prohibited_length 12
+ #define FL_status_string_prohibited_not_length 16
+ #define FL_status_string_range_length 7
+ #define FL_status_string_range_not_length 11
+ #define FL_status_string_read_length 6
+ #define FL_status_string_read_not_length 10
+ #define FL_status_string_read_only_length 11
+ #define FL_status_string_ready_length 7
+ #define FL_status_string_ready_not_length 11
+ #define FL_status_string_recurse_length 9
+ #define FL_status_string_recurse_not_length 13
+ #define FL_status_string_relative_length 10
+ #define FL_status_string_relative_not_length 14
+ #define FL_status_string_require_length 9
+ #define FL_status_string_require_not_length 13
+ #define FL_status_string_resource_length 10
+ #define FL_status_string_resource_not_length 14
+ #define FL_status_string_search_length 8
+ #define FL_status_string_search_not_length 12
+ #define FL_status_string_schedule_length 10
+ #define FL_status_string_schedule_not_length 14
+ #define FL_status_string_signal_length 8
+ #define FL_status_string_signal_not_length 12
+ #define FL_status_string_space_length 7
+ #define FL_status_string_space_not_length 11
+ #define FL_status_string_stop_length 6
+ #define FL_status_string_stop_not_length 10
+ #define FL_status_string_string_length 8
+ #define FL_status_string_string_not_length 12
+ #define FL_status_string_string_too_large_length 18
+ #define FL_status_string_string_too_small_length 18
+ #define FL_status_string_supported_length 11
+ #define FL_status_string_supported_not_length 15
+ #define FL_status_string_syntax_length 8
+ #define FL_status_string_syntax_not_length 12
+ #define FL_status_string_user_length 6
+ #define FL_status_string_user_not_length 10
+ #define FL_status_string_utf_length 5
+ #define FL_status_string_utf_not_length 9
+ #define FL_status_string_valid_length 7
+ #define FL_status_string_valid_not_length 11
+ #define FL_status_string_value_length 7
+ #define FL_status_string_value_not_length 11
+ #define FL_status_string_wait_length 6
+ #define FL_status_string_wait_not_length 10
+ #define FL_status_string_warn_length 6
+ #define FL_status_string_warn_not_length 10
+ #define FL_status_string_world_length 7
+ #define FL_status_string_world_not_length 11
+ #define FL_status_string_write_length 7
+ #define FL_status_string_write_not_length 11
+ #define FL_status_string_write_only_length 12
#endif // _di_F_status_basic_
#ifndef _di_F_status_array_
--- /dev/null
+#include "control_group.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_fll_control_group_prepare_
+ f_return_status fll_control_group_prepare(const f_control_group_t control_group) {
+ f_status_t status = F_none;
+
+ if (control_group.path.used) {
+ status = f_directory_exists(control_group.path.string);
+ if (F_status_is_error(status)) return status;
+
+ if (status == F_false) {
+ return F_status_set_error(F_directory_not);
+ }
+ }
+
+ f_string_length_t length = 0;
+
+ for (f_array_length_t i = 0; i < control_group.groups.used; ++i) {
+
+ if (!control_group.groups.array[i].used) continue;
+
+ length = control_group.path.used + control_group.groups.array[i].used;
+
+ char path[length + 1];
+
+ if (control_group.path.used) {
+ memcpy(path, control_group.path.string, control_group.path.used);
+ }
+
+ memcpy(path + control_group.path.used, control_group.groups.array[i].string, control_group.groups.array[i].used);
+ path[length] = 0;
+
+ status = fl_directory_create(path, length, f_file_mode_all_rwx);
+ if (F_status_is_error(status)) break;
+ } // for
+
+ if (F_status_is_error(status)) {
+ return status;
+ }
+
+ return F_none;
+ }
+#endif // _di_fll_control_group_prepare_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/**
+ * FLL - Level 2
+ *
+ * Project: Control Group
+ * API Version: 0.5
+ * Licenses: lgplv2.1
+ *
+ * Provides control group (cgroup) related functionality.
+ */
+#ifndef _FLL_control_h
+#define _FLL_control_h
+
+// libc includes
+
+// fll-0 includes
+#include <level_0/type.h>
+#include <level_0/status.h>
+#include <level_0/memory.h>
+#include <level_0/string.h>
+#include <level_0/utf.h>
+#include <level_0/control_group.h>
+#include <level_0/directory.h>
+#include <level_0/file.h>
+#include <level_0/path.h>
+
+// fll-1 includes
+#include <level_1/control_group.h>
+#include <level_1/directory.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Make sure all directories specified in groups exist, creating all directories in the path.
+ *
+ * This does not, however, create the control_group.path and will error out if that directory does not exist.
+ *
+ * @param control
+ * The control group(s) to ensure the directories exist.
+ *
+ * @return
+ * F_none on success.
+ * F_directory_not (with error bit) if control_group.path does not exist.
+ *
+ * Errors (with error bit) from: f_directory_exists().
+ * Errors (with error bit) from: fl_directory_create().
+ *
+ * @see f_directory_exists()
+ * @see fl_directory_create()
+ */
+#ifndef _di_fll_control_group_prepare_
+ extern f_return_status fll_control_group_prepare(const f_control_group_t control_group);
+#endif // _di_fll_control_group_prepare_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _FLL_control_h
--- /dev/null
+# fss-0000
--- /dev/null
+# fss-0000
+
+f_type
+f_status
+f_memory
+f_string
+f_utf
+f_control_group
+f_directory
+f_file
+f_path
+fl_control_group
+fl_directory
--- /dev/null
+# fss-0001
+
+project_name fll_control_group
+
+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
+build_libraries-individual -lfl_control_group -lfl_directory -lf_directory -lf_file -lf_memory -lf_path -lf_utf
+build_sources_library control_group.c
+build_sources_program
+build_sources_headers control_group.h
+build_sources_script
+build_sources_setting
+build_script yes
+build_shared yes
+build_static yes
+
+path_headers level_2
+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
+defines_static
+defines_shared
+
+flags_all -z now -g -fdiagnostics-color=always
+flags_shared
+flags_static
+flags_library -fPIC
+flags_program -fPIE
} fll_error_print_t;
#define fll_error_print_t_initialize { \
- f_macro_file_t_initialize(f_type_error, f_type_descriptor_error, f_file_flag_write_only), \
+ f_macro_file_t_initialize2(f_type_error, f_type_descriptor_error, f_file_flag_write_only), \
f_console_verbosity_normal, \
fll_error_print_error, \
f_color_set_t_initialize, \
}
#define fll_macro_error_print_t_initialize(to, verbosity, prefix, context, notable) { to, verbosity, prefix, context, notable }
- #define fll_macro_error_print_t_initialize_debug() fll_macro_error_print_t_initialize(f_macro_file_t_initialize(f_type_debug, f_type_descriptor_debug, f_file_flag_write_only), f_console_verbosity_normal, fll_error_print_debug, f_color_set_t_initialize, f_color_set_t_initialize)
- #define fll_macro_error_print_t_initialize_warning() fll_macro_error_print_t_initialize(f_macro_file_t_initialize(f_type_warning, f_type_descriptor_warning, f_file_flag_write_only), f_console_verbosity_normal, fll_error_print_warning, f_color_set_t_initialize, f_color_set_t_initialize)
+ #define fll_macro_error_print_t_initialize_debug() fll_macro_error_print_t_initialize(f_macro_file_t_initialize2(f_type_debug, f_type_descriptor_debug, f_file_flag_write_only), f_console_verbosity_normal, fll_error_print_debug, f_color_set_t_initialize, f_color_set_t_initialize)
+ #define fll_macro_error_print_t_initialize_warning() fll_macro_error_print_t_initialize(f_macro_file_t_initialize2(f_type_warning, f_type_descriptor_warning, f_file_flag_write_only), f_console_verbosity_normal, fll_error_print_warning, f_color_set_t_initialize, f_color_set_t_initialize)
#endif // _di_fll_error_print_t_
#ifdef __cplusplus
#ifndef _FLL_execute_h
#define _FLL_execute_h
+// include pre-requirements
+#define _GNU_SOURCE
+
// libc includes
#include <memory.h>
#include <sched.h>
#include <level_0/string.h>
#include <level_0/utf.h>
#include <level_0/capability.h>
+#include <level_0/control_group.h>
#include <level_0/environment.h>
#include <level_0/execute.h>
#include <level_0/file.h>
#include <level_0/signal.h>
// fll-1 includes
+#include <level_1/control_group.h>
#include <level_1/environment.h>
#include <level_1/execute.h>
#include <level_1/string.h>
* Otherwise, this returns F_child and assigns the child's return code to result for the child process.
* The caller is expected to handle the appropriate exit procedures and memory deallocation for the child process when F_child is returned.
*
- * This returns F_capability, F_group, and F_user only for the child process and must be treated the same as F_child for the purposes of understanding what the current process is.
+ * This returns F_capability, F_group, and F_user only by the child process and must be treated the same as F_child for the purposes of understanding what the current process is.
* These are essentialy F_child with explicit error codes that are returned instead of performing the desired execution.
*
+ * This returns F_control_group and F_schedule only by the parent process and represents that the child process could not be executed.
+ *
* @param program
* The name or path of the program.
* The string pointer may be set to 0, to designate that the first index in arguments is assumed to be the program.
*
* @return
* F_none on success.
+ * F_child on success but this is the child thread.
* F_capability (with error bit) on failure to set capabilities in the child (only the child process returns this).
+ * F_control_group (with error bit) on failure to set capabilities in the child (only the parent process returns this).
* F_child (with error bit) on any failure without an explicit failure code (like F_group) before calling execute but this is the child thread.
* F_failure (with error bit) on execution failure.
* F_fork (with error bit) on fork failure.
* F_group (with error bit) on failure to set GID in the child (only the child process returns this).
* F_nice (with error bit) on failure to set process niceness in the child (only the child process returns this).
* F_pipe (with error bit) on pipe failure.
- * F_schedule (with error bit) on failure to set scheduler in the child (only the child process returns this).
+ * F_schedule (with error bit) on failure to set scheduler in the child (only the parent 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().
* @see f_environment_get()
* @see f_file_exists()
* @see f_signal_set_handle()
+ * @see fl_control_group_apply()
* @see fl_environment_path_explode_dynamic()
* @see fl_string_append()
* @see fl_string_dynamic_terminate()
#endif // !defined(_di_fll_execute_arguments_add_parameter_) || !defined(_di_fll_execute_arguments_add_parameter_set_) || !defined(_di_fll_execute_arguments_dynamic_add_parameter_) || !defined(_di_fll_execute_arguments_dynamic_add_parameter_set_)
#if !defined(_di_fll_execute_program_)
- f_return_status private_fll_execute_as(const fl_execute_as_t as, fl_execute_parameter_t * const parameter, int *result) {
+ f_return_status private_fll_execute_as_child(const fl_execute_as_t as, fl_execute_parameter_t * const parameter, int *result) {
if (as.nice) {
errno = 0;
}
}
- if (as.scheduler) {
- const int process_id = getpid();
-
- struct sched_param parameter_schedule;
- parameter_schedule.sched_priority = as.scheduler->priority;
-
- errno = 0;
-
- if (sched_setscheduler(process_id, as.scheduler->policy, ¶meter_schedule) == -1) {
- *result = -1;
-
- if (parameter && parameter->option & fl_execute_parameter_option_exit) {
- exit(*result);
- }
-
- return F_status_set_error(F_schedule);
- }
- }
-
if (as.capability) {
const f_status_t status = f_capability_process_set(as.capability);
#endif // !defined(_di_fll_execute_program_)
#if !defined(_di_fll_execute_program_)
+ f_return_status private_fll_execute_as_parent(const fl_execute_as_t as, const pid_t id_child, fl_execute_parameter_t * const parameter, char *result) {
+
+ if (as.scheduler) {
+ struct sched_param parameter_schedule;
+ parameter_schedule.sched_priority = as.scheduler->priority;
+
+ errno = 0;
+
+ if (sched_setscheduler(id_child, as.scheduler->policy, ¶meter_schedule) == -1) {
+ result[0] = '1';
+
+ return F_status_set_error(F_schedule);
+ }
+ }
+
+ if (as.control_group) {
+ if (F_status_is_error(fl_control_group_apply(*as.control_group, id_child))) {
+ result[0] = '1';
+
+ return F_status_set_error(F_control_group);
+ }
+ }
+
+ return F_none;
+ }
+#endif // !defined(_di_fll_execute_program_)
+
+#if !defined(_di_fll_execute_program_)
f_return_status private_fll_execute_fork(const f_string_t program, const f_string_t fixed_arguments[], fl_execute_parameter_t * const parameter, fl_execute_as_t * const as, int *result) {
- const pid_t process_id = fork();
+ int descriptors[2] = { -1, -1 };
+
+ if (as) {
+ if (pipe(descriptors) == -1) {
+ return F_status_set_error(F_pipe);
+ }
+ }
+
+ const pid_t id_process = fork();
+
+ if (id_process < 0) {
+ if (as) {
+ close(descriptors[0]);
+ close(descriptors[1]);
+ }
- if (process_id < 0) {
return F_status_set_error(F_fork);
}
- if (process_id) {
+ if (id_process) {
+
+ if (as) {
+
+ // close the read pipe for the parent.
+ close(descriptors[0]);
+
+ // have the parent perform all appropriate access controls and then send either '0' for no error or '1' for error to the child.
+ {
+ char string_result[2] = { '0', 0 };
+
+ const f_file_t file = f_macro_file_t_initialize2(0, descriptors[1], f_file_flag_write_only);
+
+ f_string_static_t result = f_string_static_t_initialize;
+
+ result.string = string_result;
+ result.used = 1;
+ result.size = 2;
+
+ const f_status_t status = private_fll_execute_as_parent(*as, id_process, parameter, string_result);
+
+ // inform the child that it can now safely begin (or exit).
+ if (F_status_is_error(f_file_write(file, result, 0))) {
+ string_result[0] = '1';
+ }
+
+ // close the write pipe for the parent when finished writing.
+ close(descriptors[1]);
+
+ if (F_status_is_error(status)) {
+ return status;
+ }
+ }
+ }
// have the parent wait for the child process to finish.
- waitpid(process_id, result, WUNTRACED | WCONTINUED);
+ waitpid(id_process, result, WUNTRACED | WCONTINUED);
// this must explicitly check for 0 (as opposed to checking (!result)).
if (result != 0) {
return F_none;
}
+ if (as) {
+
+ // close the write pipe for the child.
+ close(descriptors[1]);
+
+ char string_response[2] = { 0, 0 };
+
+ f_string_static_t response = f_string_static_t_initialize;
+
+ response.string = string_response;
+ response.used = 0;
+ response.size = 2;
+
+ const f_file_t file = f_macro_file_t_initialize(0, descriptors[0], f_file_flag_read_only, 1, 1);
+
+ f_file_read_block(file, &response);
+
+ if (!response.used || response.string[0] == '1') {
+ close(descriptors[0]);
+
+ if (result) {
+ *result = -1;
+ }
+
+ if (parameter && parameter->option & fl_execute_parameter_option_exit) {
+ exit(-1);
+ }
+
+ return F_child;
+ }
+ }
+
if (parameter && parameter->signals) {
f_signal_set_handle(SIG_BLOCK, ¶meter->signals->block);
f_signal_set_handle(SIG_UNBLOCK, ¶meter->signals->block_not);
}
if (as) {
- const f_status_t status = private_fll_execute_as(*as, parameter, result);
+
+ // close the write pipe for the child when done.
+ close(descriptors[0]);
+
+ const f_status_t status = private_fll_execute_as_child(*as, parameter, result);
if (F_status_is_error(status)) {
return status;
return F_status_set_error(F_pipe);
}
- const pid_t process_id = fork();
+ const pid_t id_process = fork();
- if (process_id < 0) {
+ if (id_process < 0) {
close(descriptors[0]);
close(descriptors[1]);
return F_status_set_error(F_fork);
}
- if (process_id) {
+ if (id_process) {
// close the read pipe for the parent.
close(descriptors[0]);
- // write all data, if child doesn't read this could block until child closes the pipe.
{
- const f_file_t file = f_macro_file_t_initialize(0, descriptors[1], f_file_flag_write_only);
+ char string_result[2] = { '0', 0 };
+
+ const f_file_t file = f_macro_file_t_initialize2(0, descriptors[1], f_file_flag_write_only);
+
+ f_status_t status = F_none;
+
+ // have the parent perform all appropriate access controls and then send either '0' for no error or '1' for error to the child.
+ if (as) {
+ f_string_static_t result = f_string_static_t_initialize;
- f_file_write(file, *parameter->data, 0);
+ result.string = string_result;
+ result.used = 1;
+ result.size = 2;
+
+ status = private_fll_execute_as_parent(*as, id_process, parameter, string_result);
+
+ // inform the child that it can now safely begin (or exit).
+ if (F_status_is_error(f_file_write(file, result, 0))) {
+ string_result[0] = '1';
+ }
+ }
+
+ // write all data, if child doesn't read this could block until child closes the pipe.
+ if (string_result[0] == '0') {
+ f_file_write(file, *parameter->data, 0);
+ }
// close the write pipe for the parent when finished writing.
close(descriptors[1]);
+
+ if (F_status_is_error(status)) {
+ return status;
+ }
}
// have the parent wait for the child process to finish.
- waitpid(process_id, result, WUNTRACED | WCONTINUED);
+ waitpid(id_process, result, WUNTRACED | WCONTINUED);
// this must explicitly check for 0 (as opposed to checking (!result)).
if (result != 0) {
// close the write pipe for the child.
close(descriptors[1]);
+ // wait for parent to tell child to begin.
+ if (as) {
+ char string_response[2] = { 0, 0 };
+
+ f_string_static_t response = f_string_static_t_initialize;
+
+ response.string = string_response;
+ response.used = 0;
+ response.size = 2;
+
+ const f_file_t file = f_macro_file_t_initialize(0, descriptors[0], f_file_flag_read_only, 1, 1);
+
+ f_file_read_block(file, &response);
+
+ if (!response.used || response.string[0] == '1') {
+ close(descriptors[0]);
+
+ if (result) {
+ *result = -1;
+ }
+
+ if (parameter && parameter->option & fl_execute_parameter_option_exit) {
+ exit(-1);
+ }
+
+ return F_child;
+ }
+ }
+
if (parameter && parameter->signals) {
f_signal_set_handle(SIG_BLOCK, ¶meter->signals->block);
f_signal_set_handle(SIG_UNBLOCK, ¶meter->signals->block_not);
dup2(descriptors[0], f_type_descriptor_input);
if (as) {
- const f_status_t status = private_fll_execute_as(*as, parameter, result);
+ const f_status_t status = private_fll_execute_as_child(*as, parameter, result);
if (F_status_is_error(status)) {
return status;
* @see fll_execute_program()
*/
#if !defined(_di_fll_execute_program_)
- extern f_return_status private_fll_execute_as(const fl_execute_as_t as, fl_execute_parameter_t * const parameter, int *result) f_gcc_attribute_visibility_internal;
+ extern f_return_status private_fll_execute_as_child(const fl_execute_as_t as, fl_execute_parameter_t * const parameter, int *result) f_gcc_attribute_visibility_internal;
+#endif // !defined(_di_fll_execute_program_)
+
+/**
+ * Private function for perform the execute as operations.
+ *
+ * This should be executed in the parent thread.
+ *
+ * @param as
+ * The "as" operations to perform.
+ * @param id_child
+ * The child PID.
+ * @param parameter
+ * (optional) This and most of its fields are optional and are disabled when set to 0.
+ * This function only cares about "option" on this structure.
+ * option:
+ * A bitwise set of options, such as: fl_execute_parameter_option_exit, and fl_execute_parameter_option_path.
+ * @param result
+ * A NULL termianted 2-byte string array where the first character represents the return code ('0' for success, '1' for failure).
+ *
+ * @return
+ * F_none on success.
+ * F_capability (with error bit) on failure to set capabilities.
+ * F_group (with error bit) on failure to set GID.
+ * F_nice (with error bit) on failure to set process niceness.
+ * F_schedule (with error bit) on failure to set scheduler.
+ * F_user (with error bit) on failure to set UID.
+ *
+ * @see exit()
+ * @see getpid()
+ * @see nice()
+ * @see sched_setscheduler()
+ * @see setgid()
+ * @see setgroups()
+ * @see setuid()
+ *
+ * @see f_capability_process_set()
+ * @see fll_execute_program()
+ */
+#if !defined(_di_fll_execute_program_)
+ extern f_return_status private_fll_execute_as_parent(const fl_execute_as_t as, const pid_t id_child, fl_execute_parameter_t * const parameter, char *result) f_gcc_attribute_visibility_internal;
#endif // !defined(_di_fll_execute_program_)
/**
*
* @return
* F_none on success.
- * F_capability (with error bit) on failure to set capabilities in the child (only the child process returns this).
* F_child on success but this is the child thread.
+ * F_capability (with error bit) on failure to set capabilities in the child (only the child process returns this).
+ * F_control_group (with error bit) on failure to set capabilities in the child (only the parent process returns this).
+ * F_child (with error bit) on any failure without an explicit failure code (like F_group) before calling execute but this is the child thread.
* F_failure (with error bit) on execution failure.
* F_fork (with error bit) on fork failure.
* F_group (with error bit) on failure to set GID in the child (only the child process returns this).
* F_nice (with error bit) on failure to set process niceness in the child (only the child process returns this).
- * F_schedule (with error bit) on failure to set scheduler in the child (only the child process returns this).
+ * F_pipe (with error bit) on pipe failure.
+ * F_schedule (with error bit) on failure to set scheduler in the child (only the parent process returns this).
* F_user (with error bit) on failure to set UID in the child (only the child process returns this).
*
* @see clearenv()
+ * @see close()
+ * @see dup2()
* @see execv()
* @see execvp()
* @see fork()
+ * @see pipe()
* @see waitpid()
*
* @see f_environment_set_dynamic()
* @see f_signal_set_handle()
+ * @see fl_control_group_apply()
* @see fll_execute_program()
*/
#if !defined(_di_fll_execute_program_)
*
* @return
* F_none on success.
- * F_capability (with error bit) on failure to set capabilities in the child (only the child process returns this).
* F_child on success but this is the child thread.
+ * F_capability (with error bit) on failure to set capabilities in the child (only the child process returns this).
+ * F_control_group (with error bit) on failure to set capabilities in the child (only the parent process returns this).
+ * F_child (with error bit) on any failure without an explicit failure code (like F_group) before calling execute but this is the child thread.
* F_failure (with error bit) on execution failure.
* F_fork (with error bit) on fork failure.
* F_group (with error bit) on failure to set GID in the child (only the child process returns this).
* F_nice (with error bit) on failure to set process niceness in the child (only the child process returns this).
* F_pipe (with error bit) on pipe failure.
- * F_schedule (with error bit) on failure to set scheduler in the child (only the child process returns this).
+ * F_schedule (with error bit) on failure to set scheduler in the child (only the parent process returns this).
* F_user (with error bit) on failure to set UID in the child (only the child process returns this).
*
* @see clearenv()
f_status
f_memory
f_string
+f_account
f_capability
f_environment
f_execute
f_file
f_path
f_signal
+fl_control_group
fl_environment
fl_execute
fl_string
build_indexer ar
build_language c
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_libraries-individual -lfl_control_group -lfl_environment -lfl_string -lf_account -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
return F_none;
}
+ if (fl_string_compare(string, FL_status_string_control, length, FL_status_string_control_length) == F_equal_to) {
+ *code = F_control;
+ return F_none;
+ }
+
+ if (fl_string_compare(string, FL_status_string_control_not, length, FL_status_string_control_not_length) == F_equal_to) {
+ *code = F_control_not;
+ return F_none;
+ }
+
+ if (fl_string_compare(string, FL_status_string_control_group, length, FL_status_string_control_group_length) == F_equal_to) {
+ *code = F_control_group;
+ return F_none;
+ }
+
+ if (fl_string_compare(string, FL_status_string_control_group_not, length, FL_status_string_control_group_not_length) == F_equal_to) {
+ *code = F_control_group_not;
+ return F_none;
+ }
+
if (fl_string_compare(string, FL_status_string_critical, length, FL_status_string_critical_length) == F_equal_to) {
*code = F_critical;
return F_none;
byte_dump_console_parameter_t_initialize, \
f_string_lengths_t_initialize, \
F_false, \
- f_macro_file_t_initialize(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
+ f_macro_file_t_initialize2(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
fll_error_print_t_initialize, \
0, \
0, \
control_console_parameter_t_initialize, \
f_string_lengths_t_initialize, \
F_false, \
- f_macro_file_t_initialize(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
+ f_macro_file_t_initialize2(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
fll_error_print_t_initialize, \
f_color_context_t_initialize, \
}
*/
#ifndef _controller_h
+// include pre-requirements
+#define _GNU_SOURCE
+
// libc includes
#include <sched.h>
#include <string.h>
#include <level_0/capability.h>
#include <level_0/color.h>
#include <level_0/console.h>
+#include <level_0/control_group.h>
#include <level_0/directory.h>
#include <level_0/environment.h>
#include <level_0/execute.h>
// fll-1 includes
#include <level_1/color.h>
#include <level_1/console.h>
+#include <level_1/control_group.h>
#include <level_1/fss.h>
#include <level_1/string.h>
#include <level_1/type.h>
// fll-2 includes
+#include <level_2/control_group.h>
#include <level_2/environment.h>
#include <level_2/error.h>
#include <level_2/execute.h>
controller_console_parameter_t_initialize, \
f_string_lengths_t_initialize, \
F_false, \
- f_macro_file_t_initialize(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
+ f_macro_file_t_initialize2(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
fll_error_print_t_initialize, \
fll_macro_error_print_t_initialize_warning(), \
0, \
#define controller_string_command "command"
#define controller_string_consider "consider"
#define controller_string_control "control"
+ #define controller_string_control_group "control_group"
#define controller_string_deadline "deadline"
#define controller_string_default "default"
#define controller_string_define "define"
#define controller_string_entry "entry"
#define controller_string_entries "entries"
#define controller_string_environment "environment"
+ #define controller_string_existing "existing"
#define controller_string_fail "fail"
#define controller_string_failsafe "failsafe"
#define controller_string_fifo "fifo"
#define controller_string_method "method"
#define controller_string_name "name"
#define controller_string_need "need"
+ #define controller_string_new "new"
#define controller_string_nice "nice"
#define controller_string_no "no"
#define controller_string_optional "optional"
#define controller_string_command_length 7
#define controller_string_consider_length 8
#define controller_string_control_length 7
+ #define controller_string_control_group_length 13
#define controller_string_deadline_length 8
#define controller_string_define_length 6
#define controller_string_default_length 7
#define controller_string_entry_length 5
#define controller_string_entries_length 7
#define controller_string_environment_length 11
+ #define controller_string_existing_length 8
#define controller_string_fail_length 4
#define controller_string_failsafe_length 8
#define controller_string_fifo_length 4
#define controller_string_method_length 6
#define controller_string_name_length 4
#define controller_string_need_length 4
+ #define controller_string_new_length 3
#define controller_string_nice_length 4
#define controller_string_no_length 2
#define controller_string_optional_length 8
#ifndef _di_controller_rule_t_
enum {
controller_rule_setting_type_capability = 1,
- controller_rule_setting_type_control,
+ controller_rule_setting_type_control_group,
controller_rule_setting_type_define,
controller_rule_setting_type_environment,
controller_rule_setting_type_group,
#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_scheduler 0x4
- #define controller_rule_has_user 0x8
+ #define controller_rule_has_control_group 0x1
+ #define controller_rule_has_group 0x2
+ #define controller_rule_has_nice 0x4
+ #define controller_rule_has_scheduler 0x8
+ #define controller_rule_has_user 0x10
typedef struct {
f_status_t status;
f_string_dynamic_t id;
f_string_dynamic_t name;
- f_string_dynamic_t control;
f_string_dynamic_t path;
f_string_dynamic_t script;
f_string_dynamics_t wish;
f_capability_t capability;
+ f_control_group_t control_group;
f_int32s_t groups;
fl_execute_scheduler_t scheduler;
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_capability_t_initialize, \
+ f_control_group_t_initialize, \
f_int32s_t_initialize, \
fl_execute_scheduler_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); \
fl_string_dynamic_delete(&rule.path); \
fl_string_dynamic_delete(&rule.script); \
f_macro_string_maps_t_delete_simple(rule.define) \
fl_string_dynamics_delete(&rule.want); \
fl_string_dynamics_delete(&rule.wish); \
f_capability_delete(&rule.capability); \
+ fl_control_group_delete(&rule.control_group); \
fl_type_int32s_delete(&rule.groups); \
controller_macro_rule_items_t_delete_simple(rule.items)
#endif // _di_controller_rule_t_
#endif // _di_controller_rule_error_print_
#ifndef _di_controller_rule_error_print_execute_
- void controller_rule_error_print_execute(const fll_error_print_t output, const bool script_is, const f_string_t name, const int code) {
+ void controller_rule_error_print_execute(const fll_error_print_t output, const bool script_is, const f_string_t name, const int code, const f_status_t status) {
if (output.verbosity != f_console_verbosity_quiet) {
fprintf(output.to.stream, "%c", f_string_eol_s[0]);
fprintf(output.to.stream, "%s%sThe %s '", output.context.before->string, output.prefix ? output.prefix : f_string_empty_s, script_is ? controller_string_script : controller_string_program);
fprintf(output.to.stream, "%s%s%s%s", output.context.after->string, output.notable.before->string, name ? name : f_string_empty_s, output.notable.after->string);
- if (code) {
+ if (status == F_control_group || status == F_schedule) {
+ fprintf(output.to.stream, "%s' failed due to a failure to setup the '", output.context.before->string);
+ fprintf(output.to.stream, "%s%s%s%s", output.context.after->string, output.notable.before->string, status == F_control_group ? controller_string_control_group : controller_string_scheduler, output.notable.after->string);
+ fprintf(output.to.stream, "%s'.%s%c", output.context.before->string, output.context.after->string, f_string_eol_s[0]);
+ }
+ else if (code) {
fprintf(output.to.stream, "%s' failed with the exit code '", output.context.before->string);
fprintf(output.to.stream, "%s%s%i%s", output.context.after->string, output.notable.before->string, code, output.notable.after->string);
fprintf(output.to.stream, "%s'.%s%c", output.context.before->string, output.context.after->string, f_string_eol_s[0]);
as.scheduler = &rule->scheduler;
}
- if (rule->control.used) {
- // @todo: as.controls =
+ if (rule->has & controller_rule_has_control_group) {
+ as.control_group = &rule->control_group;
+
+ // make sure all required cgroup directories exist.
+ if (rule->status == F_known_not) {
+ status = fll_control_group_prepare(rule->control_group);
+
+ if (F_status_is_error(status)) {
+ fll_error_print(data->error, F_status_set_fine(status), "fll_control_group_prepare", F_true);
+
+ rule->status = F_status_set_error(F_failure);
+ return status;
+ }
+ }
}
status = fll_environment_load_names(rule->environment, &environment);
if (F_status_is_error(status)) {
fll_error_print(data->error, F_status_set_fine(status), "fll_environment_load_names", F_true);
+
+ rule->status = F_status_set_error(F_failure);
return status;
}
}
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 ? program : arguments.used ? arguments.array[0].string : f_string_empty_s, result);
+ status = F_status_set_fine(status);
+
+ if (status == F_control_group || status == F_failure || status == F_schedule) {
+ 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, status);
}
- else if (F_status_set_fine(status) == F_file_found_not) {
+ else if (status == F_file_found_not) {
controller_rule_error_print_execute_not_found(data->error, F_false, program);
}
else {
- fll_error_print(data->error, F_status_set_fine(status), "fll_execute_program_environment", F_true);
+ fll_error_print(data->error, status, "fll_execute_program", F_true);
}
data->child = 0;
- return status;
+ return F_status_set_error(status);
}
// @todo wait for pid file or timeout.
}
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 ? program : arguments.used ? arguments.array[0].string : f_string_empty_s, result);
+ status = F_status_set_fine(status);
+
+ if (status == F_control_group || status == F_failure || status == F_schedule) {
+ 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, status);
}
- else if (F_status_set_fine(status) == F_file_found_not) {
+ else if (status == F_file_found_not) {
controller_rule_error_print_execute_not_found(data->error, F_false, program);
}
else {
- fll_error_print(data->error, F_status_set_fine(status), "fll_execute_program_environment", F_true);
+ fll_error_print(data->error, status, "fll_execute_program", F_true);
}
+
+ status = F_status_set_error(status);
}
data->child = 0;
rule->nice = 0;
f_macro_time_spec_t_clear(rule->timestamp);
+ f_macro_control_group_t_clear(rule->control_group);
rule->id.used = 0;
rule->name.used = 0;
- rule->control.used = 0;
rule->path.used = 0;
rule->scheduler.policy = 0;
rule->scheduler.priority = 0;
rule->script.used = 0;
+ for (f_array_length_t i = 0; i < rule->control_group.groups.used; ++i) {
+ rule->control_group.groups.array[i].used = 0;
+ } // for
+
+ rule->control_group.as_new = F_false;
+ rule->control_group.path.used = 0;
+ rule->control_group.groups.used = 0;
+
rule->define.used = 0;
rule->parameter.used = 0;
return F_false;
}
- rule->status = F_none;
return F_true;
}
#endif // _di_controller_rule_read_
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_control_group, cache->name_item, controller_string_control_group_length) == F_equal_to) {
+ type = controller_rule_setting_type_control_group;
}
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;
continue;
}
- if (type == controller_rule_setting_type_control || 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) {
- setting_value = &rule->control;
+ if (type == controller_rule_setting_type_control_group) {
+
+ if (cache->content_actions.array[i].used < 2 || rule->has & controller_rule_has_control_group) {
+
+ 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 two 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;
+ }
+
+ if (fl_string_dynamic_partial_compare_string(controller_string_existing, cache->buffer_item, controller_string_existing_length, cache->content_actions.array[i].array[0]) == F_equal_to) {
+ rule->control_group.as_new = F_false;
+ }
+ else if (fl_string_dynamic_partial_compare_string(controller_string_new, cache->buffer_item, controller_string_new_length, cache->content_actions.array[i].array[0]) == F_equal_to) {
+ rule->control_group.as_new = F_true;
+ }
+ else {
+ 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 unknown option '", 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%s'.%s%c", data.error.notable.after->string, 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);
+ }
+
+ continue;
+ }
+
+ rule->control_group.path.used = 0;
+
+ // @todo path prefix needs to be configurable via a parameter.
+ status = fl_string_append(f_control_group_path_system_prefix, f_control_group_path_system_prefix_length, &rule->control_group.path);
+
+ if (F_status_is_error_not(status)) {
+ status = fl_string_append(f_control_group_path_system_default, f_control_group_path_system_default_length, &rule->control_group.path);
+ }
+
+ if (F_status_is_error(status)) {
+ fll_error_print(data.error, F_status_set_fine(status), "fl_string_append", F_true);
+ }
+ else {
+ rule->control_group.groups.used = 0;
+
+ for (j = 1; j < cache->content_actions.array[i].used; ++j) {
+
+ status = fl_string_dynamics_increase(&rule->control_group.groups);
+
+ if (F_status_is_error(status)) {
+ fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamics_increase", F_true);
+ break;
+ }
+
+ rule->control_group.groups.array[rule->control_group.groups.used].used = 0;
+
+ status = fl_string_dynamic_partial_append_nulless(cache->buffer_item, cache->content_actions.array[i].array[j], &rule->control_group.groups.array[rule->control_group.groups.used]);
+
+ if (F_status_is_error(status)) {
+ fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_partial_append_nulless", F_true);
+ break;
+ }
+
+ rule->control_group.groups.used++;
+ } // for
}
- else if (type == controller_rule_setting_type_name) {
+
+ 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) {
+ return status;
+ }
+
+ rule->control_group.path.used = 0;
+
+ if (F_status_is_error_not(status_return)) {
+ status_return = status;
+ }
+
+ controller_rule_error_print(data.error, *cache, F_false);
+ continue;
+ }
+
+ rule->has |= controller_rule_has_control_group;
+
+ continue;
+ }
+
+ if (type == controller_rule_setting_type_name || type == controller_rule_setting_type_path || type == controller_rule_setting_type_script) {
+ if (type == controller_rule_setting_type_name) {
setting_value = &rule->name;
}
else if (type == controller_rule_setting_type_path) {
continue;
}
- if (type == controller_rule_setting_type_control || type == controller_rule_setting_type_name || type == controller_rule_setting_type_script) {
+ if (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);
continue;
}
- 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) {
+ 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) {
continue;
}
-
if (type == controller_rule_setting_type_scheduler) {
if (cache->content_actions.array[i].used < 1 || cache->content_actions.array[i].used > 2 || rule->has & controller_rule_has_scheduler) {
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", data.context.set.important.before->string, controller_string_control_group, data.context.set.important.after->string);
+ if (rule->has & controller_rule_has_control_group) {
+ fprintf(data.output.stream, " %s", rule->control_group.as_new ? controller_string_new : controller_string_existing);
+
+ for (i = 0; i < rule->control_group.groups.used; ++i) {
+ if (rule->control_group.groups.array[i].used) {
+ fprintf(data.output.stream, " ");
+ f_print_dynamic(data.output.stream, rule->control_group.groups.array[i]);
+ }
+ } // for
+ }
+ 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_scheduler, data.context.set.important.after->string);
if (rule->has & controller_rule_has_scheduler) {
* The name of the program or script.
* @param code
* The code returned by the executed program or script.
+ * @param status
+ * The status code representing the failure (without the error bit set).
*/
#ifndef _di_controller_rule_error_print_execute_
- extern void controller_rule_error_print_execute(const fll_error_print_t output, const bool script_is, const f_string_t name, const int code) f_gcc_attribute_visibility_internal;
+ extern void controller_rule_error_print_execute(const fll_error_print_t output, const bool script_is, const f_string_t name, const int code, const f_status_t status) f_gcc_attribute_visibility_internal;
#endif // _di_controller_rule_error_print_execute_
/**
* @param cache
* A structure for containing and caching relevant data.
* @param index
- * The position in the setting.rules array representing the rule to simulate.
+ * The position in the setting.rules array representing the rule to execute.
* @param type
* The action to perform based on the action type codes.
*
f_capability
f_color
f_console
+f_control_group
f_conversion
f_directory
f_environment
f_signal
fl_color
fl_console
+fl_control_group
fl_conversion
fl_fss
fl_iki
fl_string
fl_type
+fll_control_group
fll_environment
fll_error
fll_execute
build_indexer ar
build_language c
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-individual -lfll_control_group -lfll_environment -lfll_error -lfll_execute -lfll_fss -lfll_path -lfll_program -lfll_status -lfl_color -lfl_console -lfl_control_group -lfl_conversion -lfl_directory -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
item last
first:
+ consider script require_me
+
rule script succeed
rule script php
rule command multiple
setting:
name "Multiple Commands: id, whoami, date, etc.."
capability "all="
+ control_group new memory/example
nice 15
scheduler batch 0
#user kevin
#group list 8 root
+ need script require_me
+
+script:
+ start {
+ echo
+ echo "Current cgroup for self (PPID $PPID, PID $$) is: '$(cat /proc/self/cgroup)'"
+ sleep 20
+ }
+
command:
start {
id
# fss-000d
setting:
- name "Scipt #2"
+ name "Script #2"
need script succeed
script:
--- /dev/null
+# fss-000d
+
+setting:
+ name "Example script for needs, wants, and wishes."
+ environment PATH
+ script sh
+
+script:
+ start {
+ echo
+ echo "This should be included via a need, want, or wish."
+ echo
+ }
+
# fss-000d
setting:
- name "Scipt #1"
+ name "Script #1"
environment PATH
script sh
The "settings" Rule Type has the following FSS-0001 (Extended) Content\:
"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.
+ "control_group": 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.
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 "control", the first argument is either "existing" or "new", where for "existing" the process is run inside the existing control used by the parent and when "new" the process is executed within a new control group namespace entirely.
+
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.
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"
The "settings" Rule Type has the following FSS-0001 (Extended)\:
"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).
+ "control_group": Two or more Content, the first Content being either "existing" or "new" and the remaining 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.
fake_console_parameter_t_initialize, \
f_string_lengths_t_initialize, \
F_false, \
- f_macro_file_t_initialize(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
+ f_macro_file_t_initialize2(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
fll_error_print_t_initialize, \
0, \
0, \
}
}
else {
- fll_error_print(data.error, F_status_set_fine(*status), "fll_execute_program_environment", F_true);
+ fll_error_print(data.error, F_status_set_fine(*status), "fll_execute_program", F_true);
}
}
}
}
else if (F_status_set_fine(status) != F_failure) {
- fll_error_print(data_make->error, F_status_set_fine(status), "fll_execute_program_environment", F_true);
+ fll_error_print(data_make->error, F_status_set_fine(status), "fll_execute_program", F_true);
}
}
f_signal
fl_color
fl_console
+fl_control_group
fl_conversion
fl_directory
fl_fss
build_indexer ar
build_language c
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-individual -lfll_environment -lfll_error -lfll_execute -lfll_file -lfll_fss -lfll_path -lfll_program -lfl_color -lfl_console -lfl_control_group -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
firewall_console_parameter_t_initialize, \
f_string_lengths_t_initialize, \
F_false, \
- f_macro_file_t_initialize(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
+ f_macro_file_t_initialize2(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
fll_error_print_t_initialize, \
f_string_dynamics_t_initialize, \
f_string_dynamics_t_initialize, \
f_memory
f_string
f_utf
+f_account
f_capability
f_color
f_console
f_print
fl_color
fl_console
+fl_control_group
fl_conversion
fl_fss
fl_status
build_indexer ar
build_language c
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-individual -lfll_error -lfll_execute -lfll_fss -lfll_program -lfl_color -lfl_console -lfl_control_group -lfl_conversion -lfl_environment -lfl_fss -lfl_status -lfl_string -lf_account -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
fss_basic_list_read_console_parameter_t_initialize, \
f_string_lengths_t_initialize, \
F_false, \
- f_macro_file_t_initialize(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
+ f_macro_file_t_initialize2(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
fll_error_print_t_initialize, \
f_string_dynamic_t_initialize, \
f_fss_objects_t_initialize, \
fss_basic_list_write_console_parameter_t_initialize, \
f_string_lengths_t_initialize, \
F_false, \
- f_macro_file_t_initialize(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
+ f_macro_file_t_initialize2(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
fll_error_print_t_initialize, \
f_string_static_t_initialize, \
f_color_context_t_initialize, \
fss_basic_read_console_parameter_t_initialize, \
f_string_lengths_t_initialize, \
F_false, \
- f_macro_file_t_initialize(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
+ f_macro_file_t_initialize2(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
fll_error_print_t_initialize, \
f_string_dynamic_t_initialize, \
f_fss_objects_t_initialize, \
fss_basic_write_console_parameter_t_initialize, \
f_string_lengths_t_initialize, \
F_false, \
- f_macro_file_t_initialize(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
+ f_macro_file_t_initialize2(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
fll_error_print_t_initialize, \
f_color_context_t_initialize, \
}
fss_embedded_list_read_console_parameter_t_initialize, \
f_string_lengths_t_initialize, \
F_false, \
- f_macro_file_t_initialize(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
+ f_macro_file_t_initialize2(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
fll_error_print_t_initialize, \
f_string_dynamic_t_initialize, \
f_fss_nest_t_initialize, \
fss_embedded_list_write_console_parameter_t_initialize, \
f_string_lengths_t_initialize, \
F_false, \
- f_macro_file_t_initialize(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
+ f_macro_file_t_initialize2(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
fll_error_print_t_initialize, \
f_string_static_t_initialize, \
f_color_context_t_initialize, \
fss_extended_list_read_console_parameter_t_initialize, \
f_string_lengths_t_initialize, \
F_false, \
- f_macro_file_t_initialize(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
+ f_macro_file_t_initialize2(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
fll_error_print_t_initialize, \
f_string_dynamic_t_initialize, \
f_fss_objects_t_initialize, \
fss_extended_list_write_console_parameter_t_initialize, \
f_string_lengths_t_initialize, \
F_false, \
- f_macro_file_t_initialize(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
+ f_macro_file_t_initialize2(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
fll_error_print_t_initialize, \
f_string_static_t_initialize, \
f_color_context_t_initialize, \
fss_extended_read_console_parameter_t_initialize, \
f_string_lengths_t_initialize, \
F_false, \
- f_macro_file_t_initialize(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
+ f_macro_file_t_initialize2(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
fll_error_print_t_initialize, \
f_string_dynamic_t_initialize, \
f_fss_objects_t_initialize, \
fss_extended_write_console_parameter_t_initialize, \
f_string_lengths_t_initialize, \
F_false, \
- f_macro_file_t_initialize(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
+ f_macro_file_t_initialize2(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
fll_error_print_t_initialize, \
f_string_static_t_initialize, \
f_color_context_t_initialize, \
fss_status_code_console_parameter_t_initialize, \
f_string_lengths_t_initialize, \
F_false, \
- f_macro_file_t_initialize(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
+ f_macro_file_t_initialize2(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
fll_error_print_t_initialize, \
f_color_context_t_initialize, \
}
iki_read_console_parameter_t_initialize, \
f_string_lengths_t_initialize, \
F_false, \
- f_macro_file_t_initialize(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
+ f_macro_file_t_initialize2(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
fll_error_print_t_initialize, \
0, \
0, \
iki_write_console_parameter_t_initialize, \
f_string_lengths_t_initialize, \
F_false, \
- f_macro_file_t_initialize(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
+ f_macro_file_t_initialize2(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
fll_error_print_t_initialize, \
f_string_dynamic_t_initialize, \
f_color_context_t_initialize, \
{ \
init_console_parameter_t_initialize, \
f_string_lengths_t_initialize, \
- f_macro_file_t_initialize(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
+ f_macro_file_t_initialize2(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
fll_error_print_t_initialize, \
0, \
f_signal_t_initialize, \
status_code_console_parameter_t_initialize, \
f_string_lengths_t_initialize, \
F_false, \
- f_macro_file_t_initialize(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
+ f_macro_file_t_initialize2(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
fll_error_print_t_initialize, \
f_color_context_t_initialize, \
}