Numerous structural changes and cleanups.
Things are getting bigger so apply some more organization changes to the project structure.
Start using the pointer constant behavior.
Drafted out Control functionality.
Drafted out Task functionality, which is being considered and will be tested to see if I really want to do (keep) this.
--- /dev/null
+#include "../controller.h"
+#include "../private-common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_controller_cache_action_delete_simple_
+ void controller_cache_action_delete_simple(controller_cache_action_t *cache) {
+
+ f_string_dynamic_resize(0, &cache->name_action);
+ f_string_dynamic_resize(0, &cache->name_file);
+ f_string_dynamic_resize(0, &cache->name_item);
+ f_string_dynamic_resize(0, &cache->generic);
+ }
+#endif // _di_controller_cache_action_delete_simple_
+
+#ifndef _di_controller_cache_delete_simple_
+ void controller_cache_delete_simple(controller_cache_t *cache) {
+
+ macro_f_array_lengths_t_delete_simple(cache->ats)
+ macro_f_array_lengths_t_delete_simple(cache->stack)
+ macro_f_fss_delimits_t_delete_simple(cache->delimits)
+
+ f_string_dynamic_resize(0, &cache->buffer_file);
+ f_string_dynamic_resize(0, &cache->buffer_item);
+ f_string_dynamic_resize(0, &cache->buffer_path);
+
+ f_string_ranges_resize(0, &cache->comments);
+ f_string_ranges_resize(0, &cache->content_action);
+ f_string_ranges_resize(0, &cache->object_actions);
+ f_string_ranges_resize(0, &cache->object_items);
+
+ f_string_rangess_resize(0, &cache->content_actions);
+ f_string_rangess_resize(0, &cache->content_items);
+
+ controller_cache_action_delete_simple(&cache->action);
+ }
+#endif // _di_controller_cache_delete_simple_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.5
+ * Licenses: lgpl-2.1-or-later
+ */
+#ifndef _PRIVATE_common_cache_h
+#define _PRIVATE_common_cache_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Action related cache.
+ *
+ * line_action: The line in some file representing an Action.
+ * line_item: The line in some file representing an Item.
+ * name_action: A NULL terminated name of some Action.
+ * name_file: A NULL terminated name of some File.
+ * name_item: A NULL terminated name of some Item.
+ * generic: A NULL terminated string for general use.
+ */
+#ifndef _di_controller_cache_action_t_
+ typedef struct {
+ f_array_length_t line_action;
+ f_array_length_t line_item;
+
+ f_string_dynamic_t name_action;
+ f_string_dynamic_t name_file;
+ f_string_dynamic_t name_item;
+
+ f_string_dynamic_t generic;
+ } controller_cache_action_t;
+
+ #define controller_cache_action_t_initialize { \
+ 0, \
+ 0, \
+ f_string_dynamic_t_initialize, \
+ f_string_dynamic_t_initialize, \
+ f_string_dynamic_t_initialize, \
+ f_string_dynamic_t_initialize, \
+ }
+
+ #define macro_controller_cache_action_t_clear(cache) \
+ cache.line_action = 0; \
+ cache.line_item = 0; \
+ macro_f_string_dynamic_t_clear(cache.name_action) \
+ macro_f_string_dynamic_t_clear(cache.name_file) \
+ macro_f_string_dynamic_t_clear(cache.name_item) \
+ macro_f_string_dynamic_t_clear(cache.generic)
+#endif // _di_controller_cache_action_t_
+
+/**
+ * A cache intended for re-using memory while loading and processing rules whenever possible.
+ *
+ * timestamp: The timestamp.
+ * range_action: The Range for some Action.
+ * ats: Locations.
+ * stack: Locations within a items history used as a history stack for circular recursion prevention.
+ * comments: Comments associated with a buffer string.
+ * delimits: Delimits associated with a buffer string.
+ * content_action: The specific Content for some Action.
+ * content_actions: Content for some Action.
+ * content_items: Content for some Item.
+ * object_actions: Objects for some Action.
+ * object_items: Objects for some Item.
+ * buffer_file: A generic file related buffer.
+ * buffer_item: A generic item related buffer.
+ * buffer_path: A generic path related buffer.
+ * action: A cache for some Action, often used by error printing for reporting where an error happened.
+ */
+#ifndef _di_controller_cache_t_
+ typedef struct {
+ f_time_spec_t timestamp;
+
+ f_string_range_t range_action;
+
+ f_array_lengths_t ats;
+ f_array_lengths_t stack;
+
+ f_fss_comments_t comments;
+ f_fss_delimits_t delimits;
+
+ f_fss_content_t content_action;
+ f_fss_contents_t content_actions;
+ f_fss_contents_t content_items;
+ f_fss_objects_t object_actions;
+ f_fss_objects_t object_items;
+
+ f_string_dynamic_t buffer_file;
+ f_string_dynamic_t buffer_item;
+ f_string_dynamic_t buffer_path;
+
+ controller_cache_action_t action;
+ } controller_cache_t;
+
+ #define controller_cache_t_initialize { \
+ f_time_spec_t_initialize, \
+ f_string_range_t_initialize, \
+ f_array_lengths_t_initialize, \
+ f_array_lengths_t_initialize, \
+ f_fss_comments_t_initialize, \
+ f_fss_delimits_t_initialize, \
+ f_fss_content_t_initialize, \
+ f_fss_contents_t_initialize, \
+ f_fss_contents_t_initialize, \
+ f_fss_objects_t_initialize, \
+ f_fss_objects_t_initialize, \
+ f_string_dynamic_t_initialize, \
+ f_string_dynamic_t_initialize, \
+ f_string_dynamic_t_initialize, \
+ controller_cache_action_t_initialize, \
+ }
+#endif // _di_controller_cache_t_
+
+/**
+ * Fully deallocate all memory for the given cache without caring about return status.
+ *
+ * @param cache
+ * The cache to deallocate.
+ *
+ * @see f_string_dynamic_resize()
+ */
+#ifndef _di_controller_cache_action_delete_simple_
+ extern void controller_cache_action_delete_simple(controller_cache_action_t *cache) F_attribute_visibility_internal_d;
+#endif // _di_controller_cache_action_delete_simple_
+
+/**
+ * Fully deallocate all memory for the given cache without caring about return status.
+ *
+ * @param cache
+ * The cache to deallocate.
+ *
+ * @see macro_f_array_lengths_t_delete_simple()
+ * @see macro_f_fss_delimits_t_delete_simple()
+ *
+ * @see controller_cache_action_delete_simple()
+ * @see f_string_dynamic_resize()
+ * @see f_string_ranges_resize()
+ * @see f_string_rangess_resize()
+ */
+#ifndef _di_controller_cache_delete_simple_
+ extern void controller_cache_delete_simple(controller_cache_t *cache) F_attribute_visibility_internal_d;
+#endif // _di_controller_cache_delete_simple_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _PRIVATE_common_cache_h
--- /dev/null
+#include "../controller.h"
+#include "../private-common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_controller_entry_action_delete_simple_
+ void controller_entry_action_delete_simple(controller_entry_action_t *action) {
+
+ f_string_dynamics_resize(0, &action->parameters);
+ }
+#endif // _di_controller_entry_action_delete_simple_
+
+#ifndef _di_controller_entry_actions_delete_simple_
+ void controller_entry_actions_delete_simple(controller_entry_actions_t *actions) {
+
+ actions->used = actions->size;
+
+ while (actions->used) {
+ controller_entry_action_delete_simple(&actions->array[--actions->used]);
+ } // while
+
+ f_memory_delete(actions->size, sizeof(controller_entry_action_t), (void **) & actions->array);
+ actions->size = 0;
+ }
+#endif // _di_controller_entry_actions_delete_simple_
+
+#ifndef _di_controller_entry_actions_increase_by_
+ f_status_t controller_entry_actions_increase_by(const f_array_length_t amount, controller_entry_actions_t *actions) {
+
+ if (actions->used + amount > actions->size) {
+ if (actions->used + amount > F_array_length_t_size_d) {
+ return F_status_set_error(F_array_too_large);
+ }
+
+ const f_status_t status = f_memory_resize(actions->size, actions->used + amount, sizeof(controller_entry_action_t), (void **) & actions->array);
+
+ if (F_status_is_error_not(status)) {
+ actions->size = actions->used + amount;
+ }
+
+ return status;
+ }
+
+ return F_data_not;
+ }
+#endif // _di_controller_entry_actions_increase_by_
+
+#ifndef _di_controller_entry_item_delete_simple_
+ void controller_entry_item_delete_simple(controller_entry_item_t *item) {
+
+ f_string_dynamic_resize(0, &item->name);
+
+ controller_entry_actions_delete_simple(&item->actions);
+ }
+#endif // _di_controller_entry_item_delete_simple_
+
+#ifndef _di_controller_entry_items_delete_simple_
+ void controller_entry_items_delete_simple(controller_entry_items_t *items) {
+
+ items->used = items->size;
+
+ while (items->used) {
+ controller_entry_item_delete_simple(&items->array[--items->used]);
+ } // while
+
+ f_memory_delete(items->size, sizeof(controller_entry_item_t), (void **) & items->array);
+ items->size = 0;
+ }
+#endif // _di_controller_entry_items_delete_simple_
+
+#ifndef _di_controller_entry_items_increase_by_
+ f_status_t controller_entry_items_increase_by(const f_array_length_t amount, controller_entry_items_t *items) {
+
+ if (items->used + amount > items->size) {
+ if (items->used + amount > F_array_length_t_size_d) {
+ return F_status_set_error(F_array_too_large);
+ }
+
+ const f_status_t status = f_memory_resize(items->size, items->used + amount, sizeof(controller_entry_item_t), (void **) & items->array);
+
+ if (F_status_is_error_not(status)) {
+ items->size = items->used + amount;
+ }
+
+ return status;
+ }
+
+ return F_data_not;
+ }
+#endif // _di_controller_entry_items_increase_by_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.5
+ * Licenses: lgpl-2.1-or-later
+ */
+#ifndef _PRIVATE_common_entry_h
+#define _PRIVATE_common_entry_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * An Entry Item Action.
+ *
+ * controller_entry_action_type_*:
+ * - consider: Designate a rule to be pre-loaded.
+ * - execute: Execute into another program.
+ * - failsafe: Designate a failsafe "item".
+ * - freeze: A Rule Action for freezing.
+ * - item: A named set of Rules.
+ * - kill: A Rule Action for killing.
+ * - pause: A Rule Action for pausing.
+ * - ready: Designate readiness for special processing for Entry or Exit.
+ * - reload: A Rule Action for reloading.
+ * - restart: A Rule Action for restarting.
+ * - resume: A Rule Action for resuming.
+ * - start: A Rule Action for starting.
+ * - stop: A Rule Action for stopping.
+ * - timeout: Inline timeout settings.
+ * - thaw: A Rule Action for unfreezing.
+ *
+ * controller_entry_rule_code_*:
+ * - asynchronous: Process Rule asynchronously.
+ * - require: Require Rule operations to succeed or the Entry/Exit will fail.
+ * - wait: Wait for all existing asynchronous processes to finish before operating Rule.
+ *
+ * type: The type of Action.
+ * code: A single code or sub-type associated with the Action.
+ * line: The line number where the Entry Item begins.
+ * number: The unsigned number that some types use instead of the "parameters".
+ * status: The overall status.
+ * parameters: The values associated with the Action.
+ */
+#ifndef _di_controller_entry_action_t_
+ enum {
+ controller_entry_action_type_consider_e = 1,
+ controller_entry_action_type_execute_e,
+ controller_entry_action_type_failsafe_e,
+ controller_entry_action_type_freeze_e,
+ controller_entry_action_type_item_e,
+ controller_entry_action_type_kill_e,
+ controller_entry_action_type_pause_e,
+ controller_entry_action_type_ready_e,
+ controller_entry_action_type_reload_e,
+ controller_entry_action_type_restart_e,
+ controller_entry_action_type_resume_e,
+ controller_entry_action_type_start_e,
+ controller_entry_action_type_stop_e,
+ controller_entry_action_type_timeout_e,
+ controller_entry_action_type_thaw_e,
+ };
+
+ #define controller_entry_rule_code_asynchronous_d 0x1
+ #define controller_entry_rule_code_require_d 0x2
+ #define controller_entry_rule_code_wait_d 0x4
+
+ #define controller_entry_timeout_code_kill_d 0x1
+ #define controller_entry_timeout_code_start_d 0x2
+ #define controller_entry_timeout_code_stop_d 0x4
+
+ typedef struct {
+ uint8_t type;
+ uint8_t code;
+
+ f_array_length_t line;
+ f_number_unsigned_t number;
+
+ f_status_t status;
+
+ f_string_dynamics_t parameters;
+ } controller_entry_action_t;
+
+ #define controller_entry_action_t_initialize { \
+ 0, \
+ 0, \
+ 0, \
+ 0, \
+ F_known_not, \
+ f_string_dynamics_t_initialize, \
+ }
+#endif // _di_controller_entry_action_t_
+
+/**
+ * The Entry Item Actions.
+ *
+ * array: An array of Entry Item Actions.
+ * size: Total amount of allocated space.
+ * used: Total number of allocated spaces used.
+ */
+#ifndef _di_controller_entry_actions_t_
+ typedef struct {
+ controller_entry_action_t *array;
+
+ f_array_length_t size;
+ f_array_length_t used;
+ } controller_entry_actions_t;
+
+ #define controller_entry_actions_t_initialize { \
+ 0, \
+ 0, \
+ 0, \
+ }
+#endif // _di_controller_entry_actions_t_
+
+/**
+ * An Entry Item.
+ *
+ * line: The line number where the Entry Item begins.
+ * name: The name of the Entry Item.
+ * actions: The Actions associated with the Entry Item.
+ */
+#ifndef _di_controller_entry_item_t_
+ typedef struct {
+ f_array_length_t line;
+ f_string_dynamic_t name;
+
+ controller_entry_actions_t actions;
+ } controller_entry_item_t;
+
+ #define controller_entry_item_t_initialize \
+ { \
+ 0, \
+ f_string_dynamic_t_initialize, \
+ controller_entry_actions_t_initialize, \
+ }
+#endif // _di_controller_entry_item_t_
+
+/**
+ * An Entry Items.
+ *
+ * array: An array of Entry Items.
+ * size: Total amount of allocated space.
+ * used: Total number of allocated spaces used.
+ */
+#ifndef _di_controller_entry_items_t_
+ typedef struct {
+ controller_entry_item_t *array;
+
+ f_array_length_t size;
+ f_array_length_t used;
+ } controller_entry_items_t;
+
+ #define controller_entry_items_t_initialize { \
+ 0, \
+ 0, \
+ 0, \
+ }
+
+ #define macro_controller_entry_items_t_clear(items) \
+ items.array = 0; \
+ items.size = 0; \
+ items.used = 0;
+#endif // _di_controller_entry_items_t_
+
+/**
+ * The Entry or Exit.
+ *
+ * Entry and Exit files are essentially the same structure with minor differences in settings and behavior.
+ * The structure is identical and due to lacking any particularly good name to represent both "entry" or "exit", the name "entry" is being used for both.
+ *
+ * controller_entry_pid_*:
+ * - disable: Do not check for or create a PID file to represent the entry execution.
+ * - require: Check to see if the PID file exists for an entry at startup and then when "ready" create a pid file, display error on pid file already exists or on failure and then fail.
+ * - ready: When "ready" create a pid file, display error on failure and then fail (does not check if PID file exists).
+ *
+ * controller_entry_show_*:
+ * - normal: Do not print anything other than warnings and errors, but allow executed programs and scripts to output however they like.
+ * - init: Print like an init program, printing status of entry and rules as they are being started, stopped, etc...
+ *
+ * controller_entry_session_*:
+ * - none: No special session configuration specified, use built in defaults.
+ * - new: Designate the default to use a new session, ignoring built in defaults (passing FL_execute_parameter_option_session_d to the execute functions).
+ * - same: Designate the default to use a same session, ignoring built in defaults.
+ *
+ * status: The overall status.
+ * pid: The PID file generation setting.
+ * session: The default session settings (when NULL, no default is specified).
+ * show: The show setting for controlling what to show when executing entry items and rules.
+ * timeout_kill: The timeout to wait relating to using a kill signal.
+ * timeout_start: The timeout to wait relating to starting a process.
+ * timeout_stop: The timeout to wait relating to stopping a process.
+ * items: The array of entry items.
+ */
+#ifndef _di_controller_entry_t_
+ enum {
+ controller_entry_pid_disable_e = 0,
+ controller_entry_pid_require_e,
+ controller_entry_pid_ready_e,
+ };
+
+ enum {
+ controller_entry_show_normal_e = 0,
+ controller_entry_show_init_e,
+ };
+
+ enum {
+ controller_entry_session_none_e = 0,
+ controller_entry_session_new_e,
+ controller_entry_session_same_e,
+ };
+
+ typedef struct {
+ f_status_t status;
+
+ uint8_t pid;
+ uint8_t session;
+ uint8_t show;
+
+ f_number_unsigned_t timeout_kill;
+ f_number_unsigned_t timeout_start;
+ f_number_unsigned_t timeout_stop;
+
+ controller_entry_items_t items;
+ } controller_entry_t;
+
+ #define controller_entry_t_initialize { \
+ F_known_not, \
+ controller_entry_pid_require_e, \
+ controller_entry_session_none_e, \
+ controller_entry_show_normal_e, \
+ 0, \
+ 0, \
+ 0, \
+ controller_entry_items_t_initialize, \
+ }
+#endif // _di_controller_entry_t_
+
+/**
+ * Fully deallocate all memory for the given entry action without caring about return status.
+ *
+ * @param action
+ * The action to deallocate.
+ *
+ * @see f_string_dynamics_resize()
+ */
+#ifndef _di_controller_entry_action_delete_simple_
+ extern void controller_entry_action_delete_simple(controller_entry_action_t *action) F_attribute_visibility_internal_d;
+#endif // _di_controller_entry_action_delete_simple_
+
+/**
+ * Fully deallocate all memory for the given entry actions without caring about return status.
+ *
+ * @param actions
+ * The entry_actions to deallocate.
+ *
+ * @see controller_entry_action_delete_simple()
+ * @see f_memory_delete()
+ */
+#ifndef _di_controller_entry_actions_delete_simple_
+ extern void controller_entry_actions_delete_simple(controller_entry_actions_t *actions) F_attribute_visibility_internal_d;
+#endif // _di_controller_entry_actions_delete_simple_
+
+/**
+ * Increase the size of the entry item actions array by the specified amount, but only if necessary.
+ *
+ * This only increases size if the current used plus amount is greater than the currently allocated size.
+ *
+ * @param amount
+ * A positive number representing how much to increase the size by.
+ * @param actions
+ * The entry item actions to resize.
+ *
+ * @return
+ * F_none on success.
+ * F_array_too_large (with error bit) if the resulting new size is bigger than the max array length.
+ *
+ * Errors (with error bit) from: f_memory_resize().
+ *
+ * @see f_memory_resize()
+ */
+#ifndef _di_controller_entry_actions_increase_by_
+ extern f_status_t controller_entry_actions_increase_by(const f_array_length_t amount, controller_entry_actions_t *actions) F_attribute_visibility_internal_d;
+#endif // _di_controller_entry_actions_increase_by_
+
+/**
+ * Fully deallocate all memory for the given entry item without caring about return status.
+ *
+ * @param item
+ * The item to deallocate.
+ *
+ * @see f_string_dynamic_resize()
+ */
+#ifndef _di_controller_entry_item_delete_simple_
+ extern void controller_entry_item_delete_simple(controller_entry_item_t *item) F_attribute_visibility_internal_d;
+#endif // _di_controller_entry_item_delete_simple_
+
+/**
+ * Fully deallocate all memory for the given entry items without caring about return status.
+ *
+ * @param items
+ * The entry_items to deallocate.
+ *
+ * @see controller_entry_item_delete_simple()
+ * @see f_memory_delete()
+ */
+#ifndef _di_controller_entry_items_delete_simple_
+ extern void controller_entry_items_delete_simple(controller_entry_items_t *items) F_attribute_visibility_internal_d;
+#endif // _di_controller_entry_items_delete_simple_
+
+/**
+ * Increase the size of the entry items array by the specified amount, but only if necessary.
+ *
+ * This only increases size if the current used plus amount is greater than the currently allocated size.
+ *
+ * @param amount
+ * A positive number representing how much to increase the size by.
+ * @param items
+ * The entry items to resize.
+ *
+ * @return
+ * F_none on success.
+ * F_array_too_large (with error bit) if the resulting new size is bigger than the max array length.
+ *
+ * Errors (with error bit) from: f_memory_resize().
+ *
+ * @see f_memory_resize()
+ */
+#ifndef _di_controller_entry_items_increase_by_
+ extern f_status_t controller_entry_items_increase_by(const f_array_length_t amount, controller_entry_items_t *items) F_attribute_visibility_internal_d;
+#endif // _di_controller_entry_items_increase_by_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _PRIVATE_common_entry_h
--- /dev/null
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.5
+ * Licenses: lgpl-2.1-or-later
+ */
+#ifndef _PRIVATE_common_execute_set_h
+#define _PRIVATE_common_execute_set_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * A structure for passing execution arguments to the execute functions.
+ *
+ * parameter: All parameters sent to the program on execution.
+ * as: All special properties to apply, such as cpu affinity.
+ */
+#ifndef _di_controller_execute_set_t_
+ typedef struct {
+ fl_execute_parameter_t parameter;
+ fl_execute_as_t as;
+ } controller_execute_set_t;
+
+ #define controller_execute_set_t_initialize { \
+ fl_execute_parameter_t_initialize, \
+ fl_execute_as_t_initialize \
+ }
+
+ #define macro_controller_execute_set_t_initialize(option, wait, environment, signals, main, as) { \
+ macro_fl_execute_parameter_t_initialize(option, wait, environment, signals, main), \
+ as, \
+ }
+#endif // _di_controller_execute_set_t_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _PRIVATE_common_execute_set_h
--- /dev/null
+#include "../controller.h"
+#include "../private-common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_controller_lock_delete_mutex_
+ void controller_lock_delete_mutex(f_thread_mutex_t *mutex) {
+
+ const f_status_t status = f_thread_mutex_delete(mutex);
+
+ if (F_status_is_error(status)) {
+ if (F_status_set_fine(status) == F_busy) {
+ if (f_thread_mutex_delete(mutex) == F_none) {
+ mutex = 0;
+ }
+ }
+ }
+ else {
+ mutex = 0;
+ }
+ }
+#endif // _di_controller_lock_delete_mutex_
+
+#ifndef _di_controller_lock_delete_rw_
+ void controller_lock_delete_rw(f_thread_lock_t *lock) {
+
+ const f_status_t status = f_thread_lock_delete(lock);
+
+ if (F_status_is_error(status)) {
+ if (F_status_set_fine(status) == F_busy) {
+ if (f_thread_lock_delete(lock) == F_none) {
+ lock = 0;
+ }
+ }
+ }
+ else {
+ lock = 0;
+ }
+ }
+#endif // _di_controller_lock_delete_rw_
+
+#ifndef _di_controller_lock_delete_simple_
+ void controller_lock_delete_simple(controller_lock_t *lock) {
+
+ controller_lock_delete_mutex(&lock->print);
+ controller_lock_delete_mutex(&lock->alert);
+
+ controller_lock_delete_rw(&lock->process);
+ controller_lock_delete_rw(&lock->rule);
+
+ f_thread_condition_delete(&lock->alert_condition);
+ }
+#endif // _di_controller_lock_delete_simple_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.5
+ * Licenses: lgpl-2.1-or-later
+ */
+#ifndef _PRIVATE_common_lock_h
+#define _PRIVATE_common_lock_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * A structure for sharing mutexes globally between different threads.
+ *
+ * The print lock is intended to lock any activity printing to stdout/stderr.
+ * The alert lock is intended for a generic waiting on alerts operations.
+ * The process lock is intended to lock any activity on the processs structure.
+ * The rule lock is intended to lock any activity on the rules structure.
+ *
+ * print: The print mutex lock.
+ * alert: The alert mutex lock for waking up on alerts.
+ * process: The process r/w lock.
+ * rule: The rule r/w lock.
+ * alert_condition: The condition used to trigger alerts.
+ */
+#ifndef _di_controller_lock_t_
+ typedef struct {
+ f_thread_mutex_t print;
+ f_thread_mutex_t alert;
+
+ f_thread_lock_t process;
+ f_thread_lock_t rule;
+
+ f_thread_condition_t alert_condition;
+ } controller_lock_t;
+
+ #define controller_lock_t_initialize { \
+ f_thread_mutex_t_initialize, \
+ f_thread_mutex_t_initialize, \
+ f_thread_lock_t_initialize, \
+ f_thread_lock_t_initialize, \
+ f_thread_condition_t_initialize, \
+ }
+#endif // _di_controller_lock_t_
+
+/**
+ * Delete the mutex lock and if the mutex lock is busy, forcibly unlock it and then delete it.
+ *
+ * @param mutex
+ * The mutex lock to delete.
+ * Will be set to NULLif delete succeeded.
+ */
+#ifndef _di_controller_lock_delete_mutex_
+ extern void controller_lock_delete_mutex(f_thread_mutex_t *mutex) F_attribute_visibility_internal_d;
+#endif // _di_controller_lock_delete_mutex_
+
+/**
+ * Delete the r/w lock and if the r/w lock is busy, forcibly unlock it and then delete it.
+ *
+ * @param lock
+ * The r/w lock to delete.
+ * Will be set to NULL if delete succeeded.
+ */
+#ifndef _di_controller_lock_delete_rw_
+ extern void controller_lock_delete_rw(f_thread_lock_t *lock) F_attribute_visibility_internal_d;
+#endif // _di_controller_lock_delete_rw_
+
+/**
+ * Fully deallocate all memory for the given lock without caring about return status.
+ *
+ * @param lock
+ * The lock to deallocate.
+ *
+ * @see f_thread_lock_delete()
+ * @see f_thread_mutex_delete()
+ */
+#ifndef _di_controller_lock_delete_simple_
+ extern void controller_lock_delete_simple(controller_lock_t *lock) F_attribute_visibility_internal_d;
+#endif // _di_controller_lock_delete_simple_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _PRIVATE_common_lock_h
--- /dev/null
+#include "../controller.h"
+#include "../private-common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_controller_pids_increase_
+ f_status_t controller_pids_increase(controller_pids_t *pids) {
+
+ if (pids->used + 1 > pids->size) {
+ f_array_length_t size = pids->used + controller_common_allocation_small_d;
+
+ if (size > F_array_length_t_size_d) {
+ if (pids->used + 1 > F_array_length_t_size_d) {
+ return F_status_set_error(F_array_too_large);
+ }
+
+ size = F_array_length_t_size_d;
+ }
+
+ return controller_pids_resize(size, pids);
+ }
+
+ return F_data_not;
+ }
+#endif // _di_controller_pids_increase_
+
+#ifndef _di_controller_pids_resize_
+ f_status_t controller_pids_resize(const f_array_length_t length, controller_pids_t *pids) {
+
+ f_status_t status = F_none;
+
+ status = f_memory_resize(pids->size, length, sizeof(controller_rule_t), (void **) & pids->array);
+
+ if (F_status_is_error_not(status)) {
+ pids->size = length;
+
+ if (pids->used > pids->size) {
+ pids->used = length;
+ }
+ }
+
+ return status;
+ }
+#endif // _di_controller_pids_resize_
+
+#ifndef _di_controller_process_delete_simple_
+ void controller_process_delete_simple(controller_process_t *process) {
+
+ if (process->id_thread) {
+ f_thread_signal(process->id_thread, F_signal_kill);
+ f_thread_join(process->id_thread, 0);
+
+ process->id_thread = 0;
+ }
+
+ f_thread_condition_delete(&process->wait);
+
+ controller_lock_delete_rw(&process->lock);
+ controller_lock_delete_rw(&process->active);
+ controller_lock_delete_mutex(&process->wait_lock);
+
+ controller_cache_delete_simple(&process->cache);
+ controller_pids_resize(0, &process->childs);
+ controller_rule_delete_simple(&process->rule);
+
+ f_string_dynamics_resize(0, &process->path_pids);
+
+ macro_f_array_lengths_t_delete_simple(process->stack)
+ }
+#endif // _di_controller_process_delete_simple_
+
+#ifndef _di_controller_processs_delete_simple_
+ void controller_processs_delete_simple(controller_processs_t *processs) {
+
+ controller_processs_resize(0, processs);
+ }
+#endif // _di_controller_processs_delete_simple_
+
+#ifndef _di_controller_processs_increase_
+ f_status_t controller_processs_increase(controller_processs_t *processs) {
+
+ if (processs->used + 1 > processs->size) {
+ f_array_length_t size = processs->used + controller_common_allocation_small_d;
+
+ if (size > F_array_length_t_size_d) {
+ if (processs->used + 1 > F_array_length_t_size_d) {
+ return F_status_set_error(F_array_too_large);
+ }
+
+ size = F_array_length_t_size_d;
+ }
+
+ return controller_processs_resize(size, processs);
+ }
+
+ return F_data_not;
+ }
+#endif // _di_controller_processs_increase_
+
+#ifndef _di_controller_processs_resize_
+ f_status_t controller_processs_resize(const f_array_length_t length, controller_processs_t *processs) {
+
+ f_status_t status = F_none;
+
+ for (f_array_length_t i = length; i < processs->size; ++i) {
+
+ if (processs->array[i]) {
+ controller_process_delete_simple(processs->array[i]);
+
+ f_memory_delete(1, sizeof(f_array_length_t *), (void **) & processs->array[i]);
+ }
+ } // for
+
+ status = f_memory_resize(processs->size, length, sizeof(controller_process_t), (void **) & processs->array);
+
+ if (F_status_is_error_not(status) && length) {
+
+ controller_process_t *process = 0;
+
+ // The lock must be initialized, but only once, so initialize immediately upon allocation.
+ for (; processs->size < length; ++processs->size) {
+
+ status = f_memory_new(1, sizeof(controller_process_t), (void **) &processs->array[processs->size]);
+
+ if (F_status_is_error_not(status)) {
+ process = processs->array[processs->size];
+
+ status = f_thread_lock_create(0, &process->lock);
+ }
+
+ if (F_status_is_error_not(status)) {
+ status = f_thread_lock_create(0, &process->active);
+ }
+
+ if (F_status_is_error_not(status)) {
+ status = f_thread_condition_create(0, &process->wait);
+ }
+
+ if (F_status_is_error_not(status)) {
+ status = f_thread_mutex_create(0, &process->wait_lock);
+ }
+
+ if (F_status_is_error(status)) {
+ processs->size = length;
+
+ return status;
+ }
+ else {
+ for (f_array_length_t i = 0; i < controller_rule_action_type__enum_size_e; ++i) {
+ process->rule.status[i] = F_known_not;
+ } // for
+ }
+ } // for
+
+ processs->size = length;
+
+ if (processs->used > processs->size) {
+ processs->used = length;
+ }
+ }
+
+ return status;
+ }
+#endif // _di_controller_processs_resize_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.5
+ * Licenses: lgpl-2.1-or-later
+ */
+#ifndef _PRIVATE_common_process_h
+#define _PRIVATE_common_process_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * An array of PIDs.
+ *
+ * array: An array of rule PIDs.
+ * size: Total amount of allocated space.
+ * used: Total number of allocated spaces used.
+ */
+#ifndef _di_controller_pids_t_
+ typedef struct {
+ pid_t *array;
+
+ f_array_length_t size;
+ f_array_length_t used;
+ } controller_pids_t;
+
+ #define controller_pids_t_initialize { \
+ 0, \
+ 0, \
+ 0, \
+ }
+#endif // _di_controller_pids_t_
+
+/**
+ * A Rule Process.
+ *
+ * This refers to "process" as in the processing of a single rule for the given Rule ID and does not refer to "process" as in a CPU Process.
+ *
+ * The "cache" should only be used by the function processing/executing the process and as such should not require a write lock on the "process".
+ * There should only be a single thread running any given Rule process at a time, guaranteeing the cache to not need read/write locks.
+ *
+ * Process States:
+ * - idle: No process is running for this rule.
+ * - busy: A process is actively using this, and is running synchronously.
+ * - active: A process is actively using this, and is running asynchronously.
+ * - done: A process has finished running on this and there is a thread that needs to be cleaned up.
+ *
+ * Process Types:
+ * - entry: The process is started from an entry.
+ * - exit: The process is started from an exit.
+ * - control: The process is started from a control operation.
+ *
+ * id: The ID of this process relative to the processes array.
+ * result: The last return code from an execution of a process.
+ * status: The last execution status of the process.
+ * state: The state of the process.
+ * action: The action being performed.
+ * options: Configuration options for this asynchronous thread.
+ * child: The process id of a child process, if one is running (when forking to execute a child process).
+ * id_thread: The thread id, a valid ID when state is "active", and an invalid ID when the state is "busy".
+ * lock: A read/write lock on the structure.
+ * active: A read/write lock representing that something is currently using this (read locks = in use, write lock = begin deleting).
+ * wait: A thread condition to tell a process waiting process that the rule has is done being processed.
+ * wait_lock: A mutex lock for working with "wait".
+ * cache: The cache used in this process.
+ * stack: A stack used to represent dependencies as Rule ID's to avoid circular rule dependencies (If Rule A waits on Rule B, then Rule B must not wait on Rule A).
+ * rule: A copy of the rule actively being executed.
+ * main_data: Used for passing the controller_main_t data to the process thread (to populate controller_global_t).
+ * main_setting: Used for passing the controller_setting_t data to the process thread (to populate controller_global_t).
+ * main_thread: Used for passing the controller_thread_t data to the process thread (to populate controller_global_t).
+ */
+#ifndef _di_controller_process_t_
+ #define controller_process_option_asynchronous_d 0x1
+ #define controller_process_option_require_d 0x2
+ #define controller_process_option_simulate_d 0x4
+ #define controller_process_option_validate_d 0x8
+ #define controller_process_option_wait_d 0x10
+
+ enum {
+ controller_process_state_idle_e = 1,
+ controller_process_state_busy_e,
+ controller_process_state_active_e,
+ controller_process_state_done_e,
+ };
+
+ enum {
+ controller_process_type_entry_e = 1,
+ controller_process_type_exit_e,
+ controller_process_type_control_e,
+ };
+
+ typedef struct {
+ f_array_length_t id;
+
+ uint8_t state;
+ uint8_t action;
+ uint8_t options;
+ uint8_t type;
+
+ int result;
+
+ f_thread_id_t id_thread;
+ f_thread_lock_t lock;
+ f_thread_lock_t active;
+ f_thread_condition_t wait;
+ f_thread_mutex_t wait_lock;
+
+ controller_cache_t cache;
+ f_array_lengths_t stack;
+
+ f_string_dynamics_t path_pids;
+
+ controller_pids_t childs;
+ controller_rule_t rule;
+
+ void *main_data;
+ void *main_setting;
+ void *main_thread;
+ } controller_process_t;
+
+ #define controller_process_t_initialize { \
+ 0, \
+ 0, \
+ 0, \
+ 0, \
+ 0, \
+ 0, \
+ f_thread_id_t_initialize, \
+ f_thread_lock_t_initialize, \
+ f_thread_lock_t_initialize, \
+ f_thread_condition_t_initialize, \
+ controller_cache_t_initialize, \
+ f_array_lengths_t_initialize, \
+ f_string_dynamics_t_initialize, \
+ controller_pids_t_initialize, \
+ controller_rule_t_initialize, \
+ 0, \
+ 0, \
+ 0, \
+ }
+#endif // _di_controller_process_t_
+
+/**
+ * The Rule Processes.
+ *
+ * Each process is a pointer of a process, to preserve memory locations that may ultimately change due to the resizing the array.
+ *
+ * array: An array of rule processes.
+ * size: Total amount of allocated space.
+ * used: Total number of allocated spaces used.
+ */
+#ifndef _di_controller_processs_t_
+ typedef struct {
+ controller_process_t **array;
+
+ f_array_length_t size;
+ f_array_length_t used;
+ } controller_processs_t;
+
+ #define controller_processs_t_initialize { \
+ 0, \
+ 0, \
+ 0, \
+ }
+#endif // _di_controller_processs_t_
+
+/**
+ * Increase the size of the pid array, but only if necessary.
+ *
+ * If the given length is too large for the buffer, then attempt to set max buffer size (F_array_length_t_size_d).
+ * If already set to the maximum buffer size, then the resize will fail.
+ *
+ * @param pids
+ * The pid array to resize.
+ *
+ * @return
+ * F_none on success.
+ * F_data_not on success, but there is no reason to increase size (used + controller_common_allocation_small_d <= size).
+ *
+ * F_array_too_large (with error bit) if the new array length is too large.
+ * F_memory_not (with error bit) on out of memory.
+ * F_parameter (with error bit) if a parameter is invalid.
+ *
+ * @see controller_pids_resize()
+ */
+#ifndef _di_controller_pids_increase_
+ extern f_status_t controller_pids_increase(controller_pids_t *pids) F_attribute_visibility_internal_d;
+#endif // _di_controller_rule_increase_
+
+/**
+ * Resize the pid array.
+ *
+ * @param length
+ * The new size to use.
+ * @param pids
+ * The pid array to resize.
+ *
+ * @return
+ * F_none on success.
+ *
+ * F_memory_not (with error bit) on out of memory.
+ * F_parameter (with error bit) if a parameter is invalid.
+ *
+ * @see f_memory_resize()
+ */
+#ifndef _di_controller_pids_resize_
+ extern f_status_t controller_pids_resize(const f_array_length_t length, controller_pids_t *pids) F_attribute_visibility_internal_d;
+#endif // _di_controller_pids_resize_
+
+/**
+ * Fully deallocate all memory for the given process without caring about return status.
+ *
+ * @param process
+ * The process to deallocate.
+ *
+ * @see f_string_dynamic_resize()
+ * @see f_thread_condition_delete()
+ * @see f_thread_mutex_delete()
+ */
+#ifndef _di_controller_process_delete_simple_
+ extern void controller_process_delete_simple(controller_process_t *process) F_attribute_visibility_internal_d;
+#endif // _di_controller_process_delete_simple_
+
+/**
+ * Fully deallocate all memory for the given processs without caring about return status.
+ *
+ * @param processs
+ * The process array to deallocate.
+ *
+ * @see controller_processs_resize()
+ */
+#ifndef _di_controller_processs_delete_simple_
+ extern void controller_processs_delete_simple(controller_processs_t *processs) F_attribute_visibility_internal_d;
+#endif // _di_controller_processs_delete_simple_
+
+/**
+ * Increase the size of the rule array, but only if necessary.
+ *
+ * If the given length is too large for the buffer, then attempt to set max buffer size (F_array_length_t_size_d).
+ * If already set to the maximum buffer size, then the resize will fail.
+ *
+ * @param processs
+ * The process array to resize.
+ *
+ * @return
+ * F_none on success.
+ * F_data_not on success, but there is no reason to increase size (used + controller_common_allocation_small_d <= size).
+ *
+ * F_array_too_large (with error bit) if the new array length is too large.
+ * F_memory_not (with error bit) on out of memory.
+ * F_parameter (with error bit) if a parameter is invalid.
+ *
+ * @see controller_processs_resize()
+ */
+#ifndef _di_controller_processs_increase_
+ extern f_status_t controller_processs_increase(controller_processs_t *processs) F_attribute_visibility_internal_d;
+#endif // _di_controller_rule_increase_
+
+/**
+ * Resize the rule array.
+ *
+ * @param length
+ * The new size to use.
+ * @param processs
+ * The process array to resize.
+ *
+ * @return
+ * F_none on success.
+ *
+ * Errors (with error bit) from: controller_process_delete_simple().
+ * Errors (with error bit) from: f_memory_resize().
+ * Errors (with error bit) from: f_thread_condition_create().
+ * Errors (with error bit) from: f_thread_lock_create().
+ *
+ * @see controller_process_delete_simple()
+ * @see f_memory_resize()
+ * @see f_thread_condition_create()
+ * @see f_thread_lock_create()
+ */
+#ifndef _di_controller_processs_resize_
+ extern f_status_t controller_processs_resize(const f_array_length_t length, controller_processs_t *processs) F_attribute_visibility_internal_d;
+#endif // _di_controller_processs_resize_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _PRIVATE_common_process_h
--- /dev/null
+#include "../controller.h"
+#include "../private-common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_controller_rule_action_delete_simple_
+ void controller_rule_action_delete_simple(controller_rule_action_t *action) {
+
+ f_string_dynamics_resize(0, &action->parameters);
+ }
+#endif // _di_controller_rule_action_delete_simple_
+
+#ifndef _di_controller_rule_actions_delete_simple_
+ void controller_rule_actions_delete_simple(controller_rule_actions_t *actions) {
+
+ actions->used = actions->size;
+
+ while (actions->used) {
+ controller_rule_action_delete_simple(&actions->array[--actions->used]);
+ } // while
+
+ f_memory_delete(actions->size, sizeof(controller_rule_action_t), (void **) & actions->array);
+ actions->size = 0;
+ }
+#endif // _di_controller_rule_actions_delete_simple_
+
+#ifndef _di_controller_rule_actions_increase_by_
+ f_status_t controller_rule_actions_increase_by(const f_array_length_t amount, controller_rule_actions_t *actions) {
+
+ if (actions->used + amount > actions->size) {
+ if (actions->used + amount > F_array_length_t_size_d) {
+ return F_status_set_error(F_array_too_large);
+ }
+
+ const f_status_t status = f_memory_resize(actions->size, actions->used + amount, sizeof(controller_rule_action_t), (void **) & actions->array);
+
+ if (F_status_is_error_not(status)) {
+ actions->size = actions->used + amount;
+ }
+
+ return status;
+ }
+
+ return F_data_not;
+ }
+#endif // _di_controller_rule_actions_increase_by_
+
+#ifndef _di_controller_rule_delete_simple_
+ void controller_rule_delete_simple(controller_rule_t * const rule) {
+
+ f_string_dynamic_resize(0, &rule->alias);
+ f_string_dynamic_resize(0, &rule->name);
+ f_string_dynamic_resize(0, &rule->path);
+ f_string_dynamic_resize(0, &rule->script);
+
+ f_string_maps_resize(0, &rule->define);
+ f_string_maps_resize(0, &rule->parameter);
+
+ f_string_dynamics_resize(0, &rule->environment);
+
+ macro_f_int32s_t_delete_simple(rule->affinity)
+ macro_f_control_group_t_delete_simple(rule->cgroup)
+ macro_f_int32s_t_delete_simple(rule->groups)
+ macro_f_limit_sets_t_delete_simple(rule->limits)
+
+ if (rule->capability) {
+ f_capability_delete(&rule->capability);
+ }
+
+ controller_rule_ons_delete_simple(&rule->ons);
+ controller_rule_items_delete_simple(&rule->items);
+ }
+#endif // _di_controller_rule_delete_simple_
+
+#ifndef _di_controller_rule_item_delete_simple_
+ void controller_rule_item_delete_simple(controller_rule_item_t *item) {
+
+ f_string_dynamic_resize(0, &item->pid_file);
+
+ controller_rule_actions_delete_simple(&item->actions);
+ }
+#endif // _di_controller_rule_item_delete_simple_
+
+#ifndef _di_controller_rule_items_delete_simple_
+ void controller_rule_items_delete_simple(controller_rule_items_t *items) {
+
+ items->used = items->size;
+
+ while (items->used) {
+ controller_rule_item_delete_simple(&items->array[--items->used]);
+ } // while
+
+ f_memory_delete(items->size, sizeof(controller_rule_item_t), (void **) & items->array);
+ items->size = 0;
+ }
+#endif // _di_controller_rule_items_delete_simple_
+
+#ifndef _di_controller_rule_on_delete_simple_
+ void controller_rule_on_delete_simple(controller_rule_on_t *on) {
+
+ f_string_dynamics_resize(0, &on->need);
+ f_string_dynamics_resize(0, &on->want);
+ f_string_dynamics_resize(0, &on->wish);
+ }
+#endif // _di_controller_rule_on_delete_simple_
+
+#ifndef _di_controller_rule_ons_delete_simple_
+ void controller_rule_ons_delete_simple(controller_rule_ons_t *ons) {
+
+ ons->used = ons->size;
+
+ while (ons->used) {
+ controller_rule_on_delete_simple(&ons->array[--ons->used]);
+ } // while
+
+ f_memory_delete(ons->size, sizeof(controller_rule_on_t), (void **) & ons->array);
+ ons->size = 0;
+ }
+#endif // _di_controller_rule_ons_delete_simple_
+
+#ifndef _di_controller_rule_ons_increase_
+ f_status_t controller_rule_ons_increase(controller_rule_ons_t *ons) {
+
+ if (ons->used + 1 > ons->size) {
+ f_array_length_t size = ons->used + controller_common_allocation_small_d;
+
+ if (size > F_array_length_t_size_d) {
+ if (ons->used + 1 > F_array_length_t_size_d) {
+ return F_status_set_error(F_array_too_large);
+ }
+
+ size = F_array_length_t_size_d;
+ }
+
+ return controller_rule_ons_resize(size, ons);
+ }
+
+ return F_data_not;
+ }
+#endif // _di_controller_rule_ons_increase_
+
+#ifndef _di_controller_rule_ons_resize_
+ f_status_t controller_rule_ons_resize(const f_array_length_t length, controller_rule_ons_t *ons) {
+
+ for (f_array_length_t i = length; i < ons->size; ++i) {
+ controller_rule_on_delete_simple(&ons->array[i]);
+ } // for
+
+ const f_status_t status = f_memory_resize(ons->size, length, sizeof(controller_rule_on_t), (void **) & ons->array);
+
+ if (F_status_is_error_not(status)) {
+ ons->size = length;
+
+ if (ons->used > ons->size) {
+ ons->used = length;
+ }
+ }
+
+ return status;
+ }
+#endif // _di_controller_rule_ons_resize_
+
+#ifndef _di_controller_rules_delete_simple_
+ void controller_rules_delete_simple(controller_rules_t *rules) {
+
+ controller_rules_resize(0, rules);
+ }
+#endif // _di_controller_rules_delete_simple_
+
+#ifndef _di_controller_rules_increase_
+ f_status_t controller_rules_increase(controller_rules_t *rules) {
+
+ if (rules->used + 1 > rules->size) {
+ f_array_length_t size = rules->used + controller_common_allocation_small_d;
+
+ if (size > F_array_length_t_size_d) {
+ if (rules->used + 1 > F_array_length_t_size_d) {
+ return F_status_set_error(F_array_too_large);
+ }
+
+ size = F_array_length_t_size_d;
+ }
+
+ return controller_rules_resize(size, rules);
+ }
+
+ return F_data_not;
+ }
+#endif // _di_controller_rules_increase_
+
+#ifndef _di_controller_rules_resize_
+ f_status_t controller_rules_resize(const f_array_length_t length, controller_rules_t *rules) {
+
+ for (f_array_length_t i = length; i < rules->size; ++i) {
+ controller_rule_delete_simple(&rules->array[i]);
+ } // for
+
+ const f_status_t status = f_memory_resize(rules->size, length, sizeof(controller_rule_t), (void **) & rules->array);
+
+ if (F_status_is_error_not(status)) {
+ rules->size = length;
+
+ if (rules->used > rules->size) {
+ rules->used = length;
+ }
+ }
+
+ return status;
+ }
+#endif // _di_controller_rules_resize_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.5
+ * Licenses: lgpl-2.1-or-later
+ */
+#ifndef _PRIVATE_common_rule_h
+#define _PRIVATE_common_rule_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * The Rule "rerun" item for controlling re-execution.
+ *
+ * count: A count of the number of executions.
+ * delay: The time to wait before attempting to re-run.
+ * max: The maximum number of times to re-run (with 0 representing re-run infinitely) for executions.
+ */
+#ifndef _di_controller_rule_rerun_item_t_
+ typedef struct {
+ bool reset;
+
+ f_number_unsigned_t count;
+ f_number_unsigned_t delay;
+ f_number_unsigned_t max;
+ } controller_rule_rerun_item_t;
+
+ #define controller_rule_rerun_item_initialize { \
+ F_false, \
+ 0, \
+ 5000, \
+ 0, \
+ }
+#endif // _di_controller_rule_rerun_item_t_
+
+/**
+ * The Rule "rerun" values for controlling re-execution.
+ *
+ * controller_rule_rerun_is_*:
+ * - failure: The success re-run is enabled.
+ * - failure_reset: Reset success counter when failure is returned.
+ * - success: The success re-run is enabled.
+ * - success_reset: Reset failure counter when success is returned.
+ *
+ * is: A bitwise set of options to designate whether rerun is enabled or not and other options.
+ * count_failure: A count of the number of failed executions.
+ * count_success: A count of the number of successful executions.
+ * delay_failure: The time to wait before attempting to "rerun" for failed executions.
+ * delay_success: The time to wait before attempting to "rerun" for successful executions.
+ * max_failure: The maximum number of times to "rerun" (with 0 representing "rerun" infinitely) for failed executions.
+ * max_success: The maximum number of times to "rerun" (with 0 representing "rerun" infinitely) for successful executions.
+ */
+#ifndef _di_controller_rule_rerun_t_
+ #define controller_rule_rerun_is_failure_d 0x1
+ #define controller_rule_rerun_is_failure_reset_d 0x2
+ #define controller_rule_rerun_is_success_d 0x4
+ #define controller_rule_rerun_is_success_reset_d 0x8
+
+ typedef struct {
+ uint8_t is;
+
+ controller_rule_rerun_item_t failure;
+ controller_rule_rerun_item_t success;
+ } controller_rule_rerun_t;
+
+ #define controller_rule_rerun_initialize { \
+ 0, \
+ controller_rule_rerun_item_initialize, \
+ controller_rule_rerun_item_initialize, \
+ }
+#endif // _di_controller_rule_rerun_t_
+
+/**
+ * A Rule Action.
+ *
+ * controller_rule_action_method_*:
+ * - extended: Designate that this Action is represented using FSS Extended.
+ * - extended_list: Designate that this Action is represented using FSS Extended List.
+ *
+ * controller_rule_action_type_*:
+ * - freeze: The Freeze execution instructions.
+ * - group: The Group setting.
+ * - kill: The Kill execution instructions.
+ * - pause: The Pause execution instructions.
+ * - pid_file: The PID file setting.
+ * - rerun: The Re-run execution after success or failure.
+ * - reload: The Reload execution instructions.
+ * - restart: The Restart execution instructions.
+ * - resume: The Resume execution instructions.
+ * - start: The Start execution instructions.
+ * - stop: The Stop execution instructions.
+ * - thaw: The Thaw execution instructions.
+ * - user: The User setting.
+ * - with: The With flags.
+ *
+ * type: The Rule Action type.
+ * line: The line number where the Rule Action begins.
+ * status: The last execution status of the Rule Action.
+ * parameters: All parameters associated with the Rule Action.
+ */
+#ifndef _di_controller_rule_action_t_
+ #define controller_rule_action_method_string_extended_s "FSS-0001 (Extended)"
+ #define controller_rule_action_method_string_extended_list_s "FSS-0003 (Extended List)"
+
+ #define controller_rule_action_method_string_extended_s_length 19
+ #define controller_rule_action_method_string_extended_list_s_length 24
+
+ enum {
+ controller_rule_action_method_extended_e = 1,
+ controller_rule_action_method_extended_list_e,
+ };
+
+ enum {
+ controller_rule_action_type_freeze_e = 1,
+ controller_rule_action_type_group_e,
+ controller_rule_action_type_kill_e,
+ controller_rule_action_type_pause_e,
+ controller_rule_action_type_pid_file_e,
+ controller_rule_action_type_reload_e,
+ controller_rule_action_type_rerun_e,
+ controller_rule_action_type_restart_e,
+ controller_rule_action_type_resume_e,
+ controller_rule_action_type_start_e,
+ controller_rule_action_type_stop_e,
+ controller_rule_action_type_thaw_e,
+ controller_rule_action_type_user_e,
+ controller_rule_action_type_with_e,
+
+ // designate the largest value in the enum, the '__' is intended.
+ controller_rule_action_type__enum_size_e,
+ };
+
+ // Execute type starts at 0 because it is intended to be used as an index within a static array.
+ enum {
+ controller_rule_action_type_execute_freeze_e = 0,
+ controller_rule_action_type_execute_kill_e,
+ controller_rule_action_type_execute_pause_e,
+ controller_rule_action_type_execute_reload_e,
+ controller_rule_action_type_execute_restart_e,
+ controller_rule_action_type_execute_resume_e,
+ controller_rule_action_type_execute_start_e,
+ controller_rule_action_type_execute_stop_e,
+ controller_rule_action_type_execute_thaw_e,
+
+ // designate the largest value in the enum, the '__' is intended.
+ controller_rule_action_type_execute__enum_size_e,
+ };
+
+ typedef struct {
+ uint8_t type;
+ f_array_length_t line;
+ f_status_t status;
+
+ f_string_dynamics_t parameters;
+ } controller_rule_action_t;
+
+ #define controller_rule_action_t_initialize { \
+ 0, \
+ 0, \
+ F_known_not, \
+ f_string_dynamics_t_initialize, \
+ }
+#endif // _di_controller_rule_action_t_
+
+/**
+ * The Rule Actions.
+ *
+ * array: An array of Rule Actions.
+ * size: Total amount of allocated space.
+ * used: Total number of allocated spaces used.
+ */
+#ifndef _di_controller_rule_actions_t_
+ typedef struct {
+ controller_rule_action_t *array;
+
+ f_array_length_t size;
+ f_array_length_t used;
+ } controller_rule_actions_t;
+
+ #define controller_rule_actions_t_initialize { \
+ 0, \
+ 0, \
+ 0, \
+ }
+#endif // _di_controller_rule_actions_t_
+
+/**
+ * A Rule Item.
+ *
+ * controller_rule_item_type_*:
+ * - command: A Command to execute.
+ * - script: A Script to execute.
+ * - service: A Service to execute.
+ * - setting: Settings associated with the Rule Item.
+ * - utility: A Utility to execute.
+ *
+ * type: The type of the Rule Item.
+ * with: A bitwise number representing execute "with" options.
+ * line: The line number where the Rule Item begins.
+ * reruns: An array designating rerun settings for each execution type available.
+ * actions: The actions associated with the Rule Item.
+ */
+#ifndef _di_controller_rule_item_t_
+ enum {
+ controller_rule_item_type_command_e = 1,
+ controller_rule_item_type_script_e,
+ controller_rule_item_type_service_e,
+ controller_rule_item_type_setting_e,
+ controller_rule_item_type_utility_e,
+ };
+
+ typedef struct {
+ uint8_t type;
+ uint8_t with;
+ f_array_length_t line;
+
+ f_string_dynamic_t pid_file;
+ controller_rule_rerun_t reruns[controller_rule_action_type_execute__enum_size_e];
+ controller_rule_actions_t actions;
+ } controller_rule_item_t;
+
+ #define controller_rule_item_t_initialize \
+ { \
+ 0, \
+ 0, \
+ 0, \
+ f_string_dynamic_t_initialize, \
+ { \
+ controller_rule_rerun_t_initialize, \
+ controller_rule_rerun_t_initialize, \
+ controller_rule_rerun_t_initialize, \
+ controller_rule_rerun_t_initialize, \
+ controller_rule_rerun_t_initialize, \
+ controller_rule_rerun_t_initialize, \
+ controller_rule_rerun_t_initialize, \
+ controller_rule_rerun_t_initialize, \
+ controller_rule_rerun_t_initialize, \
+ }, \
+ controller_rule_actions_t_initialize, \
+ }
+#endif // _di_controller_rule_item_t_
+
+/**
+ * The Rule Items.
+ *
+ * array: An array of Rule Items.
+ * size: Total amount of allocated space.
+ * used: Total number of allocated spaces used.
+ */
+#ifndef _di_controller_rule_items_t_
+ typedef struct {
+ controller_rule_item_t *array;
+
+ f_array_length_t size;
+ f_array_length_t used;
+ } controller_rule_items_t;
+
+ #define controller_rule_items_initialize { \
+ 0, \
+ 0, \
+ 0, \
+ }
+#endif // _di_controller_rule_items_t_
+
+/**
+ * The Rule "on" values for designating dependencies.
+ *
+ * action: The Rule Action type this "on" dependencies are associated with.
+ * need: The Rule Alias for a required Rule.
+ * want: The Rule Alias for an optional Rule that is required to succeed if found.
+ * wish: The Rule Alias for an optional Rule that is not required.
+ */
+#ifndef _di_controller_rule_on_t_
+ typedef struct {
+ uint8_t action;
+
+ f_string_dynamics_t need;
+ f_string_dynamics_t want;
+ f_string_dynamics_t wish;
+ } controller_rule_on_t;
+
+ #define controller_rule_on_initialize { \
+ 0, \
+ f_string_dynamics_t_initialize, \
+ f_string_dynamics_t_initialize, \
+ f_string_dynamics_t_initialize, \
+ }
+#endif // _di_controller_rule_on_t_
+
+/**
+ * The Rule "on" array.
+ *
+ * array: An array of Rule "on" values.
+ * size: Total amount of allocated space.
+ * used: Total number of allocated spaces used.
+ */
+#ifndef _di_controller_rule_ons_t_
+ typedef struct {
+ controller_rule_on_t *array;
+
+ f_array_length_t size;
+ f_array_length_t used;
+ } controller_rule_ons_t;
+
+ #define controller_rule_ons_t_initialize { \
+ 0, \
+ 0, \
+ 0, \
+ }
+#endif // _di_controller_rule_ons_t_
+
+/**
+ * A Rule.
+ *
+ * controller_rule_setting_type_*:
+ * - affinity: Setting type representing a affinity.
+ * - capability: Setting type representing a capability.
+ * - cgroup: Setting type representing a control group.
+ * - define: Setting type representing a define.
+ * - environment: Setting type representing a environment.
+ * - group: Setting type representing a group.
+ * - limit: Setting type representing a limit.
+ * - name: Setting type representing a name.
+ * - nice: Setting type representing a nice.
+ * - on: Setting type representing a on.
+ * - parameter: Setting type representing a parameter.
+ * - path: Setting type representing a path.
+ * - scheduler: Setting type representing a scheduler.
+ * - script: Setting type representing a script.
+ * - user: Setting type representing a user.
+ *
+ * controller_rule_has_*:
+ * - cgroup: Has type representing a control group.
+ * - group: Has type representing a group.
+ * - nice: Has type representing a nice.
+ * - scheduler: Has type representing a scheduler.
+ * - user: Has type representing a user.
+ *
+ * affinity: The cpu affinity to be used when executing the Rule.
+ * alias: The distinct ID (machine name) of the Rule, such as "service/ssh".
+ * capability: The capability setting if the Rule "has" a capability.
+ * cgroup: The control group setting if the Rule "has" a control group.
+ * define: Any defines (environment variables) made available to the Rule for IKI substitution or just as environment variables.
+ * environment: All environment variables allowed to be exposed to the Rule when processing.
+ * group: The group ID if the Rule "has" a group.
+ * groups: A set of group IDs to run the process with (first specified group is the primary group).
+ * has: Bitwise set of "has" codes representing what the Rule has.
+ * items: All items associated with the Rule.
+ * limits: The cpu/resource limits to use when executing the Rule.
+ * name: A human name for the Rule (does not have to be distinct), such as "Bash Script".
+ * nice: The niceness value if the Rule "has" nice.
+ * on: A set of parameters for defining dependencies and how they are needed, wanted, or wished for.
+ * parameter: Any parameters made available to the Rule for IKI substitution.
+ * path: The path to the Rule file.
+ * scheduler: The scheduler setting if the Rule "has" a scheduler.
+ * script: The program or path to the program of the scripting engine to use when processing scripts in this Rule.
+ * status: A set of action-specific success/failure status of the Rule. Each index represents a controller_rule_action_type_* enum value. Index 0 represents a global status.
+ * timeout_kill: The timeout to wait relating to using a kill signal.
+ * timeout_start: The timeout to wait relating to starting a process.
+ * timeout_stop: The timeout to wait relating to stopping a process.
+ * timestamp: The timestamp when the Rule was loaded.
+ * user: The User ID if the Rule "has" a user.
+ */
+#ifndef _di_controller_rule_t_
+ enum {
+ controller_rule_setting_type_affinity_e = 1,
+ controller_rule_setting_type_capability_e,
+ controller_rule_setting_type_cgroup_e,
+ controller_rule_setting_type_define_e,
+ controller_rule_setting_type_environment_e,
+ controller_rule_setting_type_group_e,
+ controller_rule_setting_type_limit_e,
+ controller_rule_setting_type_name_e,
+ controller_rule_setting_type_nice_e,
+ controller_rule_setting_type_on_e,
+ controller_rule_setting_type_parameter_e,
+ controller_rule_setting_type_path_e,
+ controller_rule_setting_type_scheduler_e,
+ controller_rule_setting_type_script_e,
+ controller_rule_setting_type_timeout_e,
+ controller_rule_setting_type_user_e,
+ };
+
+ // bitwise codes representing properties on controller_rule_t that have been found in the Rule file.
+ #define controller_rule_has_cgroup_d 0x1
+ #define controller_rule_has_environment_d 0x2
+ #define controller_rule_has_group_d 0x4
+ #define controller_rule_has_nice_d 0x8
+ #define controller_rule_has_scheduler_d 0x10
+ #define controller_rule_has_user_d 0x20
+
+ // Designate codes for timeout settings to be used during the loading of the Rule timeout settings.
+ #define controller_rule_timeout_code_kill_d 1
+ #define controller_rule_timeout_code_start_d 2
+ #define controller_rule_timeout_code_stop_d 3
+
+ typedef struct {
+ f_status_t status[controller_rule_action_type__enum_size_e];
+
+ f_number_unsigned_t timeout_kill;
+ f_number_unsigned_t timeout_start;
+ f_number_unsigned_t timeout_stop;
+
+ uint8_t has;
+ int nice;
+ uid_t user;
+ gid_t group;
+
+ f_time_spec_t timestamp;
+
+ f_string_dynamic_t alias;
+ f_string_dynamic_t name;
+ f_string_dynamic_t path;
+ f_string_dynamic_t script;
+
+ f_string_maps_t define;
+ f_string_maps_t parameter;
+
+ f_string_dynamics_t environment;
+
+ f_int32s_t affinity;
+ f_capability_t capability;
+ f_control_group_t cgroup;
+ f_int32s_t groups;
+ f_limit_sets_t limits;
+ f_execute_scheduler_t scheduler;
+
+ controller_rule_ons_t ons;
+ controller_rule_items_t items;
+ } controller_rule_t;
+
+ #define controller_rule_t_initialize { \
+ { \
+ F_known_not, \
+ F_known_not, \
+ F_known_not, \
+ F_known_not, \
+ F_known_not, \
+ F_known_not, \
+ F_known_not, \
+ F_known_not, \
+ F_known_not, \
+ F_known_not, \
+ F_known_not, \
+ F_known_not, \
+ F_known_not, \
+ F_known_not, \
+ F_known_not, \
+ }, \
+ 0, \
+ 0, \
+ 0, \
+ 0, \
+ 0, \
+ 0, \
+ 0, \
+ f_time_spec_t_initialize, \
+ f_string_dynamic_t_initialize, \
+ f_string_dynamic_t_initialize, \
+ f_string_dynamic_t_initialize, \
+ f_string_dynamic_t_initialize, \
+ f_string_maps_t_initialize, \
+ f_string_maps_t_initialize, \
+ f_string_dynamics_t_initialize, \
+ f_int32s_t_initialize, \
+ f_capability_t_initialize, \
+ f_control_group_t_initialize, \
+ f_int32s_t_initialize, \
+ f_limit_sets_t_initialize, \
+ f_execute_scheduler_t_initialize, \
+ controller_rule_ons_initialize, \
+ controller_rule_items_initialize, \
+ }
+#endif // _di_controller_rule_t_
+
+/**
+ * The Rules.
+ *
+ * array: An array of Rules.
+ * size: Total amount of allocated space.
+ * used: Total number of allocated spaces used.
+ */
+#ifndef _di_controller_rules_t_
+ typedef struct {
+ controller_rule_t *array;
+
+ f_array_length_t size;
+ f_array_length_t used;
+ } controller_rules_t;
+
+ #define controller_rules_t_initialize { \
+ 0, \
+ 0, \
+ 0, \
+ }
+#endif // _di_controller_rules_t_
+
+/**
+ * Fully deallocate all memory for the given Rule Action without caring about return status.
+ *
+ * @param action
+ * The action to deallocate.
+ *
+ * @see f_string_dynamics_resize()
+ */
+#ifndef _di_controller_rule_action_delete_simple_
+ extern void controller_rule_action_delete_simple(controller_rule_action_t *action) F_attribute_visibility_internal_d;
+#endif // _di_controller_rule_action_delete_simple_
+
+/**
+ * Fully deallocate all memory for the given Rule Actions without caring about return status.
+ *
+ * @param actions
+ * The rule_actions to deallocate.
+ *
+ * @see controller_rule_action_delete_simple()
+ * @see f_memory_delete()
+ */
+#ifndef _di_controller_rule_actions_delete_simple_
+ extern void controller_rule_actions_delete_simple(controller_rule_actions_t *actions) F_attribute_visibility_internal_d;
+#endif // _di_controller_rule_actions_delete_simple_
+
+/**
+ * Increase the size of the Rule Actions array by the specified amount, but only if necessary.
+ *
+ * This only increases size if the current used plus amount is greater than the currently allocated size.
+ *
+ * @param amount
+ * A positive number representing how much to increase the size by.
+ * @param actions
+ * The actions to resize.
+ *
+ * @return
+ * F_none on success.
+ * F_array_too_large (with error bit) if the resulting new size is bigger than the max array length.
+ *
+ * Errors (with error bit) from: f_memory_resize().
+ */
+#ifndef _di_controller_rule_actions_increase_by_
+ extern f_status_t controller_rule_actions_increase_by(const f_array_length_t amount, controller_rule_actions_t *actions) F_attribute_visibility_internal_d;
+#endif // _di_controller_rule_actions_increase_by_
+
+/**
+ * Fully deallocate all memory for the given Rule without caring about return status.
+ *
+ * @param rule
+ * The rule to deallocate.
+ *
+ * @see macro_f_control_group_t_delete_simple()
+ * @see macro_f_int32s_t_delete_simple()
+ * @see macro_f_limit_sets_t_delete_simple()
+ * @see macro_f_string_dynamics_t_delete_simple()
+ * @see macro_f_string_maps_t_delete_simple()
+ * @see macro_f_thread_condition_t_delete_simple()
+ * @see macro_f_thread_mutex_t_delete_simple()
+ *
+ * @see controller_rule_items_delete_simple()
+ * @see f_capability_delete()
+ * @see f_string_dynamic_resize()
+ */
+#ifndef _di_controller_rule_delete_simple_
+ extern void controller_rule_delete_simple(controller_rule_t *rule) F_attribute_visibility_internal_d;
+#endif // _di_controller_rule_delete_simple_
+
+/**
+ * Fully deallocate all memory for the given Rule Item without caring about return status.
+ *
+ * @param item
+ * The item to deallocate.
+ *
+ * @see f_string_dynamic_resize()
+ */
+#ifndef _di_controller_rule_item_delete_simple_
+ extern void controller_rule_item_delete_simple(controller_rule_item_t *item) F_attribute_visibility_internal_d;
+#endif // _di_controller_rule_item_delete_simple_
+
+/**
+ * Fully deallocate all memory for the given Rule Items without caring about return status.
+ *
+ * @param items
+ * The rule_items to deallocate.
+ *
+ * @see controller_rule_item_delete_simple()
+ * @see f_memory_delete()
+ */
+#ifndef _di_controller_rule_items_delete_simple_
+ extern void controller_rule_items_delete_simple(controller_rule_items_t *items) F_attribute_visibility_internal_d;
+#endif // _di_controller_rule_items_delete_simple_
+
+/**
+ * Fully deallocate all memory for the given Rule Item without caring about return status.
+ *
+ * @param on
+ * The on to deallocate.
+ *
+ * @see f_string_dynamic_resize()
+ */
+#ifndef _di_controller_rule_on_delete_simple_
+ extern void controller_rule_on_delete_simple(controller_rule_on_t *on) F_attribute_visibility_internal_d;
+#endif // _di_controller_rule_on_delete_simple_
+
+/**
+ * Fully deallocate all memory for the given Rule Items without caring about return status.
+ *
+ * @param ons
+ * The rule_ons to deallocate.
+ *
+ * @see controller_rule_on_delete_simple()
+ * @see f_memory_delete()
+ */
+#ifndef _di_controller_rule_ons_delete_simple_
+ extern void controller_rule_ons_delete_simple(controller_rule_ons_t *ons) F_attribute_visibility_internal_d;
+#endif // _di_controller_rule_ons_delete_simple_
+
+/**
+ * Increase the size of the Rule array, but only if necessary.
+ *
+ * If the given length is too large for the buffer, then attempt to set max buffer size (F_array_length_t_size_d).
+ * If already set to the maximum buffer size, then the resize will fail.
+ *
+ * @param ons
+ * The on array to resize.
+ *
+ * @return
+ * F_none on success.
+ * F_data_not on success, but there is no reason to increase size (used + controller_common_allocation_small_d <= size).
+ *
+ * F_array_too_large (with error bit) if the new array length is too large.
+ * F_memory_not (with error bit) on out of memory.
+ * F_parameter (with error bit) if a parameter is invalid.
+ *
+ * @see controller_rule_ons_resize()
+ */
+#ifndef _di_controller_rule_ons_increase_
+ extern f_status_t controller_rule_ons_increase(controller_rule_ons_t *ons) F_attribute_visibility_internal_d;
+#endif // _di_controller_rule_increase_
+
+/**
+ * Resize the Rule array.
+ *
+ * @param length
+ * The new size to use.
+ * @param ons
+ * The on array to resize.
+ *
+ * @return
+ * F_none on success.
+ *
+ * F_memory_not (with error bit) on out of memory.
+ * F_parameter (with error bit) if a parameter is invalid.
+ *
+ * @see f_memory_resize()
+ */
+#ifndef _di_controller_rule_ons_resize_
+ extern f_status_t controller_rule_ons_resize(const f_array_length_t length, controller_rule_ons_t *ons) F_attribute_visibility_internal_d;
+#endif // _di_controller_rule_ons_resize_
+
+/**
+ * Fully deallocate all memory for the given Rules without caring about return status.
+ *
+ * @param rules
+ * The rules to deallocate.
+ *
+ * @see controller_rules_resize()
+ */
+#ifndef _di_controller_rules_delete_simple_
+ extern void controller_rules_delete_simple(controller_rules_t *rules) F_attribute_visibility_internal_d;
+#endif // _di_controller_rules_delete_simple_
+
+/**
+ * Increase the size of the Rule array, but only if necessary.
+ *
+ * If the given length is too large for the buffer, then attempt to set max buffer size (F_array_length_t_size_d).
+ * If already set to the maximum buffer size, then the resize will fail.
+ *
+ * @param rules
+ * The rule array to resize.
+ *
+ * @return
+ * F_none on success.
+ * F_data_not on success, but there is no reason to increase size (used + controller_common_allocation_small_d <= size).
+ *
+ * F_array_too_large (with error bit) if the new array length is too large.
+ * F_memory_not (with error bit) on out of memory.
+ * F_parameter (with error bit) if a parameter is invalid.
+ *
+ * @see controller_rules_resize()
+ */
+#ifndef _di_controller_rules_increase_
+ extern f_status_t controller_rules_increase(controller_rules_t *rules) F_attribute_visibility_internal_d;
+#endif // _di_controller_rule_increase_
+
+/**
+ * Resize the Rule array.
+ *
+ * @param length
+ * The new size to use.
+ * @param rules
+ * The rule array to resize.
+ *
+ * @return
+ * F_none on success.
+ *
+ * F_memory_not (with error bit) on out of memory.
+ * F_parameter (with error bit) if a parameter is invalid.
+ *
+ * @see f_memory_resize()
+ */
+#ifndef _di_controller_rules_resize_
+ extern f_status_t controller_rules_resize(const f_array_length_t length, controller_rules_t *rules) F_attribute_visibility_internal_d;
+#endif // _di_controller_rules_resize_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _PRIVATE_common_rule_h
--- /dev/null
+#include "../controller.h"
+#include "../private-common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_controller_setting_delete_simple_
+ void controller_setting_delete_simple(controller_setting_t *setting) {
+
+ f_string_dynamic_resize(0, &setting->path_control);
+ f_string_dynamic_resize(0, &setting->path_cgroup);
+ f_string_dynamic_resize(0, &setting->path_pid);
+ f_string_dynamic_resize(0, &setting->path_setting);
+
+ f_string_dynamic_resize(0, &setting->name_entry);
+
+ controller_entry_items_delete_simple(&setting->entry.items);
+ controller_entry_items_delete_simple(&setting->exit.items);
+
+ controller_rules_delete_simple(&setting->rules);
+ }
+#endif // _di_controller_setting_delete_simple_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.5
+ * Licenses: lgpl-2.1-or-later
+ */
+#ifndef _PRIVATE_common_setting_h
+#define _PRIVATE_common_setting_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * All setting data.
+ *
+ * controller_setting_ready_*:
+ * - no: Entry/Exit is not ready.
+ * - wait: Entry/Exit has "ready" somewhere in the file but is not yet ready.
+ * - yes: Entry/Exit is now ready (Entry/Exit is still being processed).
+ * - done: Entry/Exit is ready and processing is complete.
+ * - fail: Entry/Exit processing failed.
+ * - abort: Abort received before finished processing Entry/Exit.
+ *
+ * controller_setting_mode_*:
+ * - program: Run as a program, exiting when finished prrocess entry (and any respective exit).
+ * - service: Run as a service, listening for requests after processing entry.
+ *
+ * interruptible: TRUE if the program responds to interrupt signals, FALSE to block/ignore interrupt signals.
+ * pid_created: TRUE if the PID file has been created.
+ * ready: State representing if the settings are all loaded and is ready to run program operations.
+ * mode: Controller setting mode based on the setting mode enumerator.
+ * control_group: Group role of the control socket.
+ * control_moode: Mode role of the control socket.
+ * control_readonly: TRUE if the control is set to readonly, FALSE otherwise.
+ * control_socket: The control socket data.
+ * control_user: User role of the control socket.
+ * failsafe_enabled: TRUE if failsafe execution is enabled, FALSE otherwise.
+ * failsafe_item_id: The Entry Item ID to execute when failsafe execution is enabled.
+ * path_cgroup: Directory path to the cgroup directory.
+ * path_control: File path to the control socket.
+ * path_pid: File path to the PID file.
+ * path_setting: File path to the setting directory.
+ * entry: The Entry settings.
+ * rules: All rules and their respective settings.
+ */
+#ifndef _di_controller_setting_t
+ enum {
+ controller_setting_ready_no_e = 0,
+ controller_setting_ready_wait_e,
+ controller_setting_ready_yes_e,
+ controller_setting_ready_done_e,
+ controller_setting_ready_fail_e,
+ controller_setting_ready_abort_e,
+ };
+
+ enum {
+ controller_setting_mode_service_e = 0,
+ controller_setting_mode_program_e,
+ };
+
+ typedef struct {
+ bool interruptible;
+ bool pid_created;
+ uint8_t ready;
+ uint8_t mode;
+
+ gid_t control_group;
+ mode_t control_mode;
+ bool control_readonly;
+ f_socket_t control_socket;
+ uid_t control_user;
+
+ bool failsafe_enabled;
+ f_array_length_t failsafe_item_id;
+
+ f_string_dynamic_t path_cgroup;
+ f_string_dynamic_t path_control;
+ f_string_dynamic_t path_pid;
+ f_string_dynamic_t path_setting;
+
+ f_string_dynamic_t name_entry;
+
+ controller_entry_t entry;
+ controller_entry_t exit;
+ controller_rules_t rules;
+ } controller_setting_t;
+
+ #define controller_setting_t_initialize { \
+ F_false, \
+ F_false, \
+ 0, \
+ 0, \
+ 0, \
+ 0, \
+ F_false, \
+ f_socket_t_initialize, \
+ 0, \
+ F_false, \
+ 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, \
+ controller_entry_t_initialize, \
+ controller_entry_t_initialize, \
+ controller_rules_t_initialize, \
+ }
+#endif // _di_controller_setting_t
+
+/**
+ * Fully deallocate all memory for the given setting without caring about return status.
+ *
+ * @param setting
+ * The setting to deallocate.
+ *
+ * @see controller_entry_delete_simple()
+ * @see controller_rules_delete_simple()
+ * @see f_string_dynamic_resize()
+ */
+#ifndef _di_controller_setting_delete_simple_
+ extern void controller_setting_delete_simple(controller_setting_t *setting) F_attribute_visibility_internal_d;
+#endif // _di_controller_setting_delete_simple_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _PRIVATE_common_setting_h
--- /dev/null
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.5
+ * Licenses: lgpl-2.1-or-later
+ */
+#ifndef _PRIVATE_common_state_h
+#define _PRIVATE_common_state_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * A structure for passing data to the interrupt state function.
+ *
+ * is_normal: Boolean designating if this is operating in a normal state.
+ * thread: The thread data.
+ */
+#ifndef _di_controller_state_interrupt_t_
+ typedef struct {
+ bool is_normal;
+ controller_thread_t *thread;
+ } controller_state_interrupt_t;
+
+ #define controller_state_interrupt_t_initialize { \
+ F_true, \
+ 0, \
+ }
+
+ #define macro_controller_state_interrupt_t_initialize(is_normal, thread) { \
+ is_normal, \
+ thread, \
+ }
+#endif // _di_controller_state_interrupt_t_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _PRIVATE_common_state_h
--- /dev/null
+#include "../controller.h"
+#include "../private-common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_controller_task_action_delete_simple_
+ void controller_task_action_delete_simple(controller_task_action_t *action) {
+
+ f_string_dynamic_resize(0, &action->help);
+ f_string_dynamics_resize(0, &action->parameters);
+ }
+#endif // _di_controller_task_action_delete_simple_
+
+#ifndef _di_controller_task_actions_delete_simple_
+ void controller_task_actions_delete_simple(controller_task_actions_t *actions) {
+
+ actions->used = actions->size;
+
+ while (actions->used) {
+ controller_task_action_delete_simple(&actions->array[--actions->used]);
+ } // while
+
+ f_memory_delete(actions->size, sizeof(controller_task_action_t), (void **) & actions->array);
+ actions->size = 0;
+ }
+#endif // _di_controller_task_actions_delete_simple_
+
+#ifndef _di_controller_task_actions_increase_by_
+ f_status_t controller_task_actions_increase_by(const f_array_length_t amount, controller_task_actions_t *actions) {
+
+ if (actions->used + amount > actions->size) {
+ if (actions->used + amount > F_array_length_t_size_d) {
+ return F_status_set_error(F_array_too_large);
+ }
+
+ const f_status_t status = f_memory_resize(actions->size, actions->used + amount, sizeof(controller_task_action_t), (void **) & actions->array);
+
+ if (F_status_is_error_not(status)) {
+ actions->size = actions->used + amount;
+ }
+
+ return status;
+ }
+
+ return F_data_not;
+ }
+#endif // _di_controller_task_actions_increase_by_
+
+#ifndef _di_controller_task_delete_simple_
+ void controller_task_delete_simple(controller_task_t * const task) {
+
+ f_string_dynamic_resize(0, &task->alias);
+ f_string_dynamic_resize(0, &task->help);
+ f_string_dynamic_resize(0, &task->name);
+ f_string_dynamic_resize(0, &task->path);
+ f_string_dynamic_resize(0, &task->script);
+
+ f_string_maps_resize(0, &task->arguments);
+ f_string_maps_resize(0, &task->defines);
+ f_string_maps_resize(0, &task->parameters);
+
+ f_string_dynamics_resize(0, &task->environment);
+
+ macro_f_int32s_t_delete_simple(task->affinity)
+ macro_f_control_group_t_delete_simple(task->cgroup)
+ macro_f_int32s_t_delete_simple(task->groups)
+ macro_f_limit_sets_t_delete_simple(task->limits)
+
+ if (task->capability) {
+ f_capability_delete(&task->capability);
+ }
+
+ controller_task_actions_delete_simple(&task->actions);
+ }
+#endif // _di_controller_task_delete_simple_
+
+#ifndef _di_controller_tasks_delete_simple_
+ void controller_tasks_delete_simple(controller_tasks_t *tasks) {
+
+ controller_tasks_resize(0, tasks);
+ }
+#endif // _di_controller_tasks_delete_simple_
+
+#ifndef _di_controller_tasks_increase_
+ f_status_t controller_tasks_increase(controller_tasks_t *tasks) {
+
+ if (tasks->used + 1 > tasks->size) {
+ f_array_length_t size = tasks->used + controller_common_allocation_small_d;
+
+ if (size > F_array_length_t_size_d) {
+ if (tasks->used + 1 > F_array_length_t_size_d) {
+ return F_status_set_error(F_array_too_large);
+ }
+
+ size = F_array_length_t_size_d;
+ }
+
+ return controller_tasks_resize(size, tasks);
+ }
+
+ return F_data_not;
+ }
+#endif // _di_controller_tasks_increase_
+
+#ifndef _di_controller_tasks_resize_
+ f_status_t controller_tasks_resize(const f_array_length_t length, controller_tasks_t *tasks) {
+
+ for (f_array_length_t i = length; i < tasks->size; ++i) {
+ controller_task_delete_simple(&tasks->array[i]);
+ } // for
+
+ const f_status_t status = f_memory_resize(tasks->size, length, sizeof(controller_task_t), (void **) & tasks->array);
+
+ if (F_status_is_error_not(status)) {
+ tasks->size = length;
+
+ if (tasks->used > tasks->size) {
+ tasks->used = length;
+ }
+ }
+
+ return status;
+ }
+#endif // _di_controller_tasks_resize_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.5
+ * Licenses: lgpl-2.1-or-later
+ */
+#ifndef _PRIVATE_common_task_h
+#define _PRIVATE_common_task_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * A Task Action.
+ *
+ * controller_task_action_method_*:
+ * - extended: Designate that this Action is represented using FSS Extended.
+ * - extended_list: Designate that this Action is represented using FSS Extended List.
+ *
+ * help: The help text associated with this action.
+ * line: The line number where the Task Action begins.
+ * parameters: All parameters associated with the Task Action.
+ * status: The last execution status of the Task Action.
+ * type: The Task Action type, this references an index in the controller_task_parameters_t for the parent Task.
+ */
+#ifndef _di_controller_task_action_t_
+ #define controller_task_action_method_string_extended_s "FSS-0001 (Extended)"
+ #define controller_task_action_method_string_extended_list_s "FSS-0003 (Extended List)"
+
+ #define controller_task_action_method_string_extended_s_length 19
+ #define controller_task_action_method_string_extended_list_s_length 24
+
+ enum {
+ controller_task_action_method_extended_e = 1,
+ controller_task_action_method_extended_list_e,
+ };
+
+ typedef struct {
+ f_status_t status;
+ f_array_length_t type;
+ f_array_length_t line;
+
+ f_string_dynamic_t help;
+ f_string_dynamics_t parameters;
+ } controller_task_action_t;
+
+ #define controller_task_action_t_initialize { \
+ F_known_not, \
+ 0, \
+ 0, \
+ f_string_dynamic_t_initialize, \
+ f_string_dynamics_t_initialize, \
+ }
+#endif // _di_controller_task_action_t_
+
+/**
+ * The Task Actions.
+ *
+ * array: An array of Task Actions.
+ * size: Total amount of allocated space.
+ * used: Total number of allocated spaces used.
+ */
+#ifndef _di_controller_task_actions_t_
+ typedef struct {
+ controller_task_action_t *array;
+
+ f_array_length_t size;
+ f_array_length_t used;
+ } controller_task_actions_t;
+
+ #define controller_task_actions_t_initialize { \
+ 0, \
+ 0, \
+ 0, \
+ }
+#endif // _di_controller_task_actions_t_
+
+/**
+ * A Task structure.
+ *
+ * controller_task_setting_type_*:
+ * - affinity: Setting type representing a affinity.
+ * - capability: Setting type representing a capability.
+ * - cgroup: Setting type representing a cgroup (control group).
+ * - define: Setting type representing a define.
+ * - environment: Setting type representing a environment.
+ * - group: Setting type representing a group.
+ * - limit: Setting type representing a limit.
+ * - name: Setting type representing a name.
+ * - nice: Setting type representing a nice.
+ * - parameter: Setting type representing a parameter.
+ * - path: Setting type representing a path.
+ * - scheduler: Setting type representing a scheduler.
+ * - script: Setting type representing a script.
+ * - user: Setting type representing a user.
+ *
+ * controller_task_has_*:
+ * - cgroup: Has type representing a cgroup (control group).
+ * - group: Has type representing a group.
+ * - nice: Has type representing a nice.
+ * - scheduler: Has type representing a scheduler.
+ * - user: Has type representing a user.
+ *
+ * affinity: The cpu affinity to be used when executing the Task.
+ * alias: The distinct ID (machine name) of the Task, such as "service/ssh".
+ * arguments: The arguments (parameters) passed to the Task, which are exposed via the IKI substitution.
+ * capability: The capability setting if the Task "has" a capability.
+ * cgroup: The cgroup (control group) setting if the Task "has" a cgroup (control group).
+ * define: Any defines (environment variables) made available to the Task for IKI substitution or just as environment variables.
+ * environment: All environment variables allowed to be exposed to the Task when processing.
+ * group: The group ID if the Task "has" a group.
+ * groups: A set of group IDs to run the process with (first specified group is the primary group).
+ * has: Bitwise set of "has" codes representing what the Task has.
+ * limits: The cpu/resource limits to use when executing the Task.
+ * name: A human name for the Task (does not have to be distinct), such as "Bash Script".
+ * nice: The niceness value if the Task "has" nice.
+ * parameter: Any parameters made available to the Task for IKI substitution.
+ * path: The path to the Task file.
+ * scheduler: The scheduler setting if the Task "has" a scheduler.
+ * script: The program or path to the program of the scripting engine to use when processing scripts in this Task.
+ * state: The current active/inactive state of the Task.
+ * status: The last returned status of the Task.
+ * timestamp: The timestamp when the Task was last updated.
+ * user: The User ID if the Task "has" a user.
+ */
+#ifndef _di_controller_task_t_
+ enum {
+ controller_task_setting_type_affinity_e = 1,
+ controller_task_setting_type_capability_e,
+ controller_task_setting_type_cgroup_e,
+ controller_task_setting_type_define_e,
+ controller_task_setting_type_environment_e,
+ controller_task_setting_type_group_e,
+ controller_task_setting_type_limit_e,
+ controller_task_setting_type_name_e,
+ controller_task_setting_type_nice_e,
+ controller_task_setting_type_parameter_e,
+ controller_task_setting_type_path_e,
+ controller_task_setting_type_scheduler_e,
+ controller_task_setting_type_script_e,
+ controller_task_setting_type_user_e,
+ };
+
+ // Bitwise codes representing properties on controller_task_t that have been found in the Task file.
+ #define controller_task_has_cgroup_d 0x1
+ #define controller_task_has_environment_d 0x2
+ #define controller_task_has_group_d 0x4
+ #define controller_task_has_nice_d 0x8
+ #define controller_task_has_scheduler_d 0x10
+ #define controller_task_has_user_d 0x20
+
+ typedef struct {
+ f_status_t state;
+ f_status_t status;
+
+ uint8_t has;
+ int nice;
+ uid_t user;
+ gid_t group;
+
+ f_time_spec_t timestamp;
+
+ f_string_dynamic_t alias;
+ f_string_dynamic_t help;
+ f_string_dynamic_t name;
+ f_string_dynamic_t path;
+ f_string_dynamic_t script;
+
+ f_string_maps_t arguments;
+ f_string_maps_t defines;
+ f_string_maps_t parameters;
+
+ f_string_dynamics_t environment;
+
+ f_int32s_t affinity;
+ f_capability_t capability;
+ f_control_group_t cgroup;
+ f_int32s_t groups;
+ f_limit_sets_t limits;
+ f_execute_scheduler_t scheduler;
+
+ controller_task_actions_t actions;
+ } controller_task_t;
+
+ #define controller_task_t_initialize { \
+ F_none, \
+ F_none, \
+ 0, \
+ 0, \
+ 0, \
+ 0, \
+ f_time_spec_t_initialize, \
+ f_string_dynamic_t_initialize, \
+ f_string_dynamic_t_initialize, \
+ f_string_dynamic_t_initialize, \
+ f_string_dynamic_t_initialize, \
+ f_string_dynamic_t_initialize, \
+ f_string_maps_t_initialize, \
+ f_string_maps_t_initialize, \
+ f_string_maps_t_initialize, \
+ f_string_dynamics_t_initialize, \
+ f_int32s_t_initialize, \
+ f_capability_t_initialize, \
+ f_control_group_t_initialize, \
+ f_int32s_t_initialize, \
+ f_limit_sets_t_initialize, \
+ f_execute_scheduler_t_initialize, \
+ controller_task_actions_t_initialize, \
+ }
+#endif // _di_controller_task_t_
+
+/**
+ * The Tasks.
+ *
+ * array: An array of Tasks.
+ * size: Total amount of allocated space.
+ * used: Total number of allocated spaces used.
+ */
+#ifndef _di_controller_tasks_t_
+ typedef struct {
+ controller_task_t *array;
+
+ f_array_length_t size;
+ f_array_length_t used;
+ } controller_tasks_t;
+
+ #define controller_tasks_t_initialize { \
+ 0, \
+ 0, \
+ 0, \
+ }
+#endif // _di_controller_tasks_t_
+
+/**
+ * Fully deallocate all memory for the given Task Action without caring about return status.
+ *
+ * @param action
+ * The action to deallocate.
+ *
+ * @see f_string_dynamics_resize()
+ */
+#ifndef _di_controller_task_action_delete_simple_
+ extern void controller_task_action_delete_simple(controller_task_action_t *action) F_attribute_visibility_internal_d;
+#endif // _di_controller_task_action_delete_simple_
+
+/**
+ * Fully deallocate all memory for the given Task Actions without caring about return status.
+ *
+ * @param actions
+ * The task_actions to deallocate.
+ *
+ * @see f_memory_delete()
+ *
+ * @see controller_task_action_delete_simple()
+ */
+#ifndef _di_controller_task_actions_delete_simple_
+ extern void controller_task_actions_delete_simple(controller_task_actions_t *actions) F_attribute_visibility_internal_d;
+#endif // _di_controller_task_actions_delete_simple_
+
+/**
+ * Increase the size of the Task Actions array by the specified amount, but only if necessary.
+ *
+ * This only increases size if the current used plus amount is greater than the currently allocated size.
+ *
+ * @param amount
+ * A positive number representing how much to increase the size by.
+ * @param actions
+ * The actions to resize.
+ *
+ * @return
+ * F_none on success.
+ * F_array_too_large (with error bit) if the resulting new size is bigger than the max array length.
+ *
+ * Errors (with error bit) from: f_memory_resize().
+ */
+#ifndef _di_controller_task_actions_increase_by_
+ extern f_status_t controller_task_actions_increase_by(const f_array_length_t amount, controller_task_actions_t *actions) F_attribute_visibility_internal_d;
+#endif // _di_controller_task_actions_increase_by_
+
+/**
+ * Fully deallocate all memory for the given Rule without caring about return status.
+ *
+ * @param task
+ * The task to deallocate.
+ *
+ * @see macro_f_control_group_t_delete_simple()
+ * @see macro_f_int32s_t_delete_simple()
+ * @see macro_f_limit_sets_t_delete_simple()
+ * @see macro_f_string_dynamics_t_delete_simple()
+ * @see macro_f_string_maps_t_delete_simple()
+ * @see macro_f_thread_condition_t_delete_simple()
+ * @see macro_f_thread_mutex_t_delete_simple()
+ *
+ * @see f_capability_delete()
+ * @see f_string_dynamic_resize()
+ *
+ * @see controller_task_items_delete_simple()
+ */
+#ifndef _di_controller_task_delete_simple_
+ extern void controller_task_delete_simple(controller_task_t *task) F_attribute_visibility_internal_d;
+#endif // _di_controller_task_delete_simple_
+
+/**
+ * Fully deallocate all memory for the given Tasks without caring about return status.
+ *
+ * @param tasks
+ * The tasks to deallocate.
+ *
+ * @see controller_tasks_resize()
+ */
+#ifndef _di_controller_tasks_delete_simple_
+ extern void controller_tasks_delete_simple(controller_tasks_t *tasks) F_attribute_visibility_internal_d;
+#endif // _di_controller_tasks_delete_simple_
+
+/**
+ * Increase the size of the Task array, but only if necessary.
+ *
+ * If the given length is too large for the buffer, then attempt to set max buffer size (F_array_length_t_size_d).
+ * If already set to the maximum buffer size, then the resize will fail.
+ *
+ * @param tasks
+ * The task array to resize.
+ *
+ * @return
+ * F_none on success.
+ * F_data_not on success, but there is no reason to increase size (used + controller_common_allocation_small_d <= size).
+ *
+ * F_array_too_large (with error bit) if the new array length is too large.
+ * F_memory_not (with error bit) on out of memory.
+ * F_parameter (with error bit) if a parameter is invalid.
+ *
+ * @see controller_tasks_resize()
+ */
+#ifndef _di_controller_tasks_increase_
+ extern f_status_t controller_tasks_increase(controller_tasks_t *tasks) F_attribute_visibility_internal_d;
+#endif // _di_controller_task_increase_
+
+/**
+ * Resize the Task array.
+ *
+ * @param length
+ * The new size to use.
+ * @param tasks
+ * The task array to resize.
+ *
+ * @return
+ * F_none on success.
+ *
+ * F_memory_not (with error bit) on out of memory.
+ * F_parameter (with error bit) if a parameter is invalid.
+ *
+ * @see f_memory_resize()
+ */
+#ifndef _di_controller_tasks_resize_
+ extern f_status_t controller_tasks_resize(const f_array_length_t length, controller_tasks_t *tasks) F_attribute_visibility_internal_d;
+#endif // _di_controller_tasks_resize_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _PRIVATE_common_task_h
--- /dev/null
+#include "../controller.h"
+#include "../private-common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_controller_thread_delete_simple_
+ void controller_thread_delete_simple(controller_thread_t *thread) {
+
+ controller_lock_delete_simple(&thread->lock);
+ controller_processs_resize(0, &thread->processs);
+ controller_cache_delete_simple(&thread->cache);
+ }
+#endif // _di_controller_thread_delete_simple_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.5
+ * Licenses: lgpl-2.1-or-later
+ */
+#ifndef _PRIVATE_common_thread_h
+#define _PRIVATE_common_thread_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * A structure for managing threads.
+ *
+ * This is essentially data shared globally between threads, about threads.
+ *
+ * The "enabled" and "signal" utilize the lock: lock.process.
+ *
+ * enabled: TRUE when threads are active, FALSE when inactive and the program is essentially shutting down, no new threads should be started when FALSE.
+ * signal: The code of any signal received.
+ * status: A status used by the main entry/rule processing thread for synchronous operations.
+ * id_cleanup: The thread ID representing the Cleanup Process.
+ * id_control: The thread ID representing the Control Process.
+ * id_entry: The thread ID representing the Entry or Exit Process.
+ * id_rule: The thread ID representing the Rule Process.
+ * id_signal: The thread ID representing the Signal Process.
+ * lock: A r/w lock for operating on this structure.
+ * processs: All Rule Process thread data.
+ * cache: A cache used by the main entry/rule processing thread for synchronous operations.
+ */
+#ifndef _di_controller_thread_t_
+ #define controller_thread_cleanup_interval_long_d 3600 // 1 hour in seconds.
+ #define controller_thread_cleanup_interval_short_d 180 // 3 minutes in seconds.
+ #define controller_thread_exit_process_cancel_wait_d 600000000 // 0.6 seconds in nanoseconds.
+ #define controller_thread_exit_process_cancel_total_d 150 // 90 seconds in multiples of wait.
+ #define controller_thread_simulation_timeout_d 200 // 0.2 seconds in milliseconds.
+
+ #define controller_thread_signal_wait_timeout_seconds_d 70
+ #define controller_thread_signal_wait_timeout_nanoseconds_d 0
+
+ #define controller_thread_lock_read_timeout_seconds_d 3
+ #define controller_thread_lock_read_timeout_nanoseconds_d 0
+ #define controller_thread_lock_write_timeout_seconds_d 3
+ #define controller_thread_lock_write_timeout_nanoseconds_d 0
+
+ #define controller_thread_wait_timeout_1_before_d 4
+ #define controller_thread_wait_timeout_2_before_d 12
+ #define controller_thread_wait_timeout_3_before_d 28
+
+ #define controller_thread_wait_timeout_1_seconds_d 0
+ #define controller_thread_wait_timeout_1_nanoseconds_d 20000000 // 0.02 seconds in nanoseconds.
+ #define controller_thread_wait_timeout_2_seconds_d 0
+ #define controller_thread_wait_timeout_2_nanoseconds_d 200000000 // 0.2 seconds in nanoseconds.
+ #define controller_thread_wait_timeout_3_seconds_d 2
+ #define controller_thread_wait_timeout_3_nanoseconds_d 0
+ #define controller_thread_wait_timeout_4_seconds_d 20
+ #define controller_thread_wait_timeout_4_nanoseconds_d 0
+
+ #define controller_thread_exit_ready_timeout_seconds_d 0
+ #define controller_thread_exit_ready_timeout_nanoseconds_d 500000000 // 0.5 seconds in nanoseconds.
+
+ /**
+ * States for enabled, designating how to stop the process.
+ *
+ * controller_thread_*:
+ * - enabled_not: The controller is no longer enabled, shut down and abort all work.
+ * - enabled: The controller is operating normally.
+ * - enabled_execute: The controller is executing another process, all running operations must terminate.
+ * - enabled_exit: The controller is shutting down, only process exit rules.
+ * - enabled_exit_execute: The controller is executing another process while in failsafe mode, all running operations must terminate.
+ * - enabled_exit_ready: The controller is shutting down, only process exit rules, and now ready to send termination signals.
+ *
+ * controller_thread_cancel_*:
+ * - signal: Cancellation is triggered by a signal.
+ * - call: Cancellation is explicitly called.
+ * - execute: Cancellation is explicitly called due to an "execute" Item Action, when not during Exit.
+ * - exit: Cancellation is explicitly called during Exit.
+ * - exit_execute: Cancellation is explicitly called due to an "execute" Item Action during Exit.
+ */
+ enum {
+ controller_thread_enabled_not_e = 0,
+ controller_thread_enabled_e,
+ controller_thread_enabled_execute_e,
+ controller_thread_enabled_exit_e,
+ controller_thread_enabled_exit_execute_e,
+ controller_thread_enabled_exit_ready_e,
+ };
+
+ enum {
+ controller_thread_cancel_signal_e = 0,
+ controller_thread_cancel_call_e,
+ controller_thread_cancel_execute_e,
+ controller_thread_cancel_exit_e,
+ controller_thread_cancel_exit_execute_e,
+ };
+
+ typedef struct {
+ uint8_t enabled;
+ int signal;
+ f_status_t status;
+
+ f_thread_id_t id_cleanup;
+ f_thread_id_t id_control;
+ f_thread_id_t id_entry;
+ f_thread_id_t id_rule;
+ f_thread_id_t id_signal;
+
+ controller_lock_t lock;
+ controller_processs_t processs;
+ controller_cache_t cache;
+ } controller_thread_t;
+
+ #define controller_thread_t_initialize { \
+ controller_thread_enabled_e, \
+ 0, \
+ F_none, \
+ f_thread_id_t_initialize, \
+ f_thread_id_t_initialize, \
+ f_thread_id_t_initialize, \
+ f_thread_id_t_initialize, \
+ f_thread_id_t_initialize, \
+ controller_lock_t_initialize, \
+ controller_processs_t_initialize, \
+ controller_cache_t_initialize, \
+ }
+#endif // _di_controller_thread_t_
+
+/**
+ * Fully deallocate all memory for the given setting without caring about return status.
+ *
+ * @param thread
+ * The thread to deallocate.
+ *
+ * @see controller_asynchronouss_resize()
+ * @see f_thread_mutex_unlock()
+ */
+#ifndef _di_controller_thread_delete_simple_
+ extern void controller_thread_delete_simple(controller_thread_t * const thread) F_attribute_visibility_internal_d;
+#endif // _di_controller_thread_delete_simple_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _PRIVATE_common_thread_h
f_print_character(f_string_eol_s[0], main->output.to.stream);
- fll_program_print_help_option(main->output.to, main->context, controller_short_control_s, controller_long_control_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, " Specify a custom control group file path, such as '" F_control_group_path_system_prefix_s F_control_group_path_system_default_s "'.");
+ fll_program_print_help_option(main->output.to, main->context, controller_short_cgroup_s, controller_long_cgroup_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, " Specify a custom control group file path, such as '" F_control_group_path_system_prefix_s F_control_group_path_system_default_s "'.");
fll_program_print_help_option(main->output.to, main->context, controller_short_daemon_s, controller_long_daemon_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, " Run in daemon only mode (do not process the entry).");
fll_program_print_help_option(main->output.to, main->context, controller_short_init_s, controller_long_init_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, " The program will run as an init replacement.");
fll_program_print_help_option(main->output.to, main->context, controller_short_interruptible_s, controller_long_interruptible_s, f_console_symbol_short_enable_s, f_console_symbol_long_enable_s, " Designate that this program can be interrupted by a signal.");
}
controller_main_delete(main);
+
return F_status_set_error(status);
}
}
if (F_status_is_error(status)) {
controller_main_delete(main);
+
return status;
}
controller_print_help(main);
controller_main_delete(main);
+
return F_none;
}
controller_unlock_print_flush(main->output.to, 0);
controller_main_delete(main);
+
return F_none;
}
controller_setting_t setting = controller_setting_t_initialize;
+ struct sockaddr_un address;
+ setting.control_socket.address = (struct sockaddr *) &address;
+ setting.control_socket.domain = f_socket_domain_file_d;
+ setting.control_socket.type = f_socket_type_stream_d;
+ setting.control_socket.length = sizeof(struct sockaddr_un);
+
+ memset(&address, 0, setting.control_socket.length);
+
if (main->remaining.used) {
status = f_string_append_nulless(arguments->argv[main->remaining.array[0]], strnlen(arguments->argv[main->remaining.array[0]], f_console_parameter_size), &setting.name_entry);
}
fll_error_print(main->error, F_status_set_fine(status), "f_string_append_nulless", F_true);
controller_main_delete(main);
+
return status;
}
fll_error_print(main->error, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true);
controller_main_delete(main);
+
return status;
}
status = fll_path_canonical(arguments->argv[location], &setting.path_setting);
if (F_status_is_error(status)) {
- fll_error_print(main->error, F_status_set_fine(status), "fll_path_canonical", F_true);
+ fll_error_file_print(main->error, F_status_set_fine(status), "fll_path_canonical", F_true, arguments->argv[location], "verify", fll_error_file_type_path_e);
}
}
else {
status = fll_path_canonical(arguments->argv[location], &setting.path_pid);
if (F_status_is_error(status)) {
- fll_error_print(main->error, F_status_set_fine(status), "fll_path_canonical", F_true);
+ fll_error_file_print(main->error, F_status_set_fine(status), "fll_path_canonical", F_true, arguments->argv[location], "verify", fll_error_file_type_path_e);
}
}
else {
}
if (F_status_is_error_not(status) && !setting.path_pid.used && !main->parameters[controller_parameter_pid_e].locations.used) {
-
if (main->parameters[controller_parameter_init_e].result == f_console_result_found_e) {
status = f_string_append(controller_path_pid_init_s, controller_path_pid_init_s_length, &setting.path_pid);
}
}
if (F_status_is_error_not(status)) {
- if (main->parameters[controller_parameter_control_e].result == f_console_result_found_e) {
+ if (main->parameters[controller_parameter_cgroup_e].result == f_console_result_found_e) {
if (main->error.verbosity != f_console_verbosity_quiet_e) {
controller_lock_print(main->error.to, 0);
fl_print_format("%c%[%SThe parameter '%]", main->error.to.stream, f_string_eol_s[0], main->error.context, main->error.prefix ? main->error.prefix : f_string_empty_s, main->error.context);
- fl_print_format("%[%s%s%]", main->error.to.stream, main->context.set.notable, f_console_symbol_long_enable_s, controller_long_control_s, main->context.set.notable);
+ fl_print_format("%[%s%s%]", main->error.to.stream, main->context.set.notable, f_console_symbol_long_enable_s, controller_long_cgroup_s, main->context.set.notable);
fl_print_format("%[' is specified, but no value is given.%]%c", main->error.to.stream, main->error.context, main->error.context, f_string_eol_s[0]);
controller_unlock_print_flush(main->error.to, 0);
status = F_status_set_error(F_parameter);
}
- else if (main->parameters[controller_parameter_control_e].locations.used) {
- const f_array_length_t location = main->parameters[controller_parameter_control_e].values.array[main->parameters[controller_parameter_control_e].values.used - 1];
+ else if (main->parameters[controller_parameter_cgroup_e].locations.used) {
+ const f_array_length_t location = main->parameters[controller_parameter_cgroup_e].values.array[main->parameters[controller_parameter_cgroup_e].values.used - 1];
if (strnlen(arguments->argv[location], f_console_parameter_size)) {
- status = fll_path_canonical(arguments->argv[location], &setting.path_control);
+ status = fll_path_canonical(arguments->argv[location], &setting.path_cgroup);
if (F_status_is_error(status)) {
- fll_error_print(main->error, F_status_set_fine(status), "fll_path_canonical", F_true);
+ fll_error_file_print(main->error, F_status_set_fine(status), "fll_path_canonical", F_true, arguments->argv[location], "verify", fll_error_file_type_path_e);
}
else {
- status = f_string_append_assure(F_path_separator_s, 1, &setting.path_control);
+ status = f_string_append_assure(F_path_separator_s, 1, &setting.path_cgroup);
if (F_status_is_error(status)) {
fll_error_print(main->error, F_status_set_fine(status), "f_string_append_assure", F_true);
}
else {
- status = f_string_dynamic_terminate_after(&setting.path_control);
+ status = f_string_dynamic_terminate_after(&setting.path_cgroup);
if (F_status_is_error(status)) {
fll_error_print(main->error, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true);
controller_lock_print(main->warning.to, 0);
fl_print_format("%c%[%SThe parameter '%]", main->warning.to.stream, f_string_eol_s[0], main->warning.context, main->warning.prefix ? main->warning.prefix : f_string_empty_s, main->warning.context);
- fl_print_format("%[%s%s%]", main->warning.to.stream, main->context.set.notable, f_console_symbol_long_enable_s, controller_long_control_s, main->context.set.notable);
+ fl_print_format("%[%s%s%]", main->warning.to.stream, main->context.set.notable, f_console_symbol_long_enable_s, controller_long_cgroup_s, main->context.set.notable);
fl_print_format("%[' must be a file directory path but instead is an empty string, falling back to the default.%]%c", main->warning.to.stream, main->warning.context, main->warning.context, f_string_eol_s[0]);
controller_unlock_print_flush(main->warning.to, 0);
f_signal_close(&main->signal);
}
- // a control file path is required.
- if (!setting.path_control.used) {
- status = f_string_append_nulless(F_control_group_path_system_prefix_s, F_control_group_path_system_prefix_s_length, &setting.path_control);
+ // A control file path is required.
+ if (!setting.path_cgroup.used) {
+ status = f_string_append_nulless(F_control_group_path_system_prefix_s, F_control_group_path_system_prefix_s_length, &setting.path_cgroup);
if (F_status_is_error_not(status)) {
- status = f_string_append_nulless(F_control_group_path_system_default_s, F_control_group_path_system_default_s_length, &setting.path_control);
+ status = f_string_append_nulless(F_control_group_path_system_default_s, F_control_group_path_system_default_s_length, &setting.path_cgroup);
}
if (F_status_is_error(status)) {
fll_error_print(main->error, F_status_set_fine(status), "f_string_append_nulless", F_true);
}
else {
- status = f_string_append_assure(F_path_separator_s, 1, &setting.path_control);
+ status = f_string_append_assure(F_path_separator_s, 1, &setting.path_cgroup);
if (F_status_is_error(status)) {
fll_error_print(main->error, F_status_set_fine(status), "f_string_append_assure", F_true);
}
else {
- status = f_string_dynamic_terminate_after(&setting.path_control);
+ status = f_string_dynamic_terminate_after(&setting.path_cgroup);
if (F_status_is_error(status)) {
fll_error_print(main->error, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true);
}
}
+ if (status != F_child && setting.path_control.used) {
+ f_socket_disconnect(&setting.control_socket, f_socket_close_read_write_e);
+
+ if (!setting.control_readonly) {
+ f_file_remove(setting.path_control.string);
+ }
+ }
+
controller_setting_delete_simple(&setting);
controller_main_delete(main);
#include <fll/level_0/pipe.h>
#include <fll/level_0/print.h>
#include <fll/level_0/signal.h>
+#include <fll/level_0/socket.h>
// fll-1 includes
#include <fll/level_1/console.h>
#define controller_path_settings_s_length 10
#define controller_path_suffix_s_length 4
- #define controller_short_control_s "c"
+ #define controller_short_cgroup_s "c"
#define controller_short_daemon_s "d"
#define controller_short_init_s "I"
#define controller_short_interruptible_s "i"
#define controller_short_uninterruptible_s "U"
#define controller_short_validate_s "v"
- #define controller_long_control_s "control"
+ #define controller_long_cgroup_s "cgroup"
#define controller_long_daemon_s "daemon"
#define controller_long_init_s "init"
#define controller_long_interruptible_s "interruptible"
controller_parameter_verbosity_debug_e,
controller_parameter_version_e,
- controller_parameter_control_e,
+ controller_parameter_cgroup_e,
controller_parameter_daemon_e,
controller_parameter_init_e,
controller_parameter_interruptible_e,
f_console_parameter_t_initialize(f_console_standard_short_verbose_s, f_console_standard_long_verbose_s, 0, 0, f_console_type_inverse_e), \
f_console_parameter_t_initialize(f_console_standard_short_debug_s, f_console_standard_long_debug_s, 0, 0, f_console_type_inverse_e), \
f_console_parameter_t_initialize(f_console_standard_short_version_s, f_console_standard_long_version_s, 0, 0, f_console_type_inverse_e), \
- f_console_parameter_t_initialize(controller_short_control_s, controller_long_control_s, 0, 1, f_console_type_normal_e), \
+ f_console_parameter_t_initialize(controller_short_cgroup_s, controller_long_cgroup_s, 0, 1, f_console_type_normal_e), \
f_console_parameter_t_initialize(controller_short_daemon_s, controller_long_daemon_s, 0, 0, f_console_type_normal_e), \
f_console_parameter_t_initialize(controller_short_init_s, controller_long_init_s, 0, 0, f_console_type_normal_e), \
f_console_parameter_t_initialize(controller_short_interruptible_s, controller_long_interruptible_s, 0, 0, f_console_type_normal_e), \
const f_string_t controller_bash_s = CONTROLLER_bash_s;
const f_string_t controller_batch_s = CONTROLLER_batch_s;
const f_string_t controller_capability_s = CONTROLLER_capability_s;
+ const f_string_t controller_cgroup_s = CONTROLLER_cgroup_s;
const f_string_t controller_create_s = CONTROLLER_create_s;
const f_string_t controller_command_s = CONTROLLER_command_s;
const f_string_t controller_consider_s = CONTROLLER_consider_s;
const f_string_t controller_control_s = CONTROLLER_control_s;
const f_string_t controller_control_group_s = CONTROLLER_control_group_s;
+ const f_string_t controller_control_mode_s = CONTROLLER_control_mode_s;
+ const f_string_t controller_control_user_s = CONTROLLER_control_user_s;
const f_string_t controller_cpu_s = CONTROLLER_cpu_s;
const f_string_t controller_core_s = CONTROLLER_core_s;
const f_string_t controller_data_s = CONTROLLER_data_s;
const f_string_t controller_yes_s = CONTROLLER_yes_s;
#endif // _di_controller_string_s_
-#ifndef _di_controller_cache_action_delete_simple_
- void controller_cache_action_delete_simple(controller_cache_action_t *cache) {
-
- f_string_dynamic_resize(0, &cache->name_action);
- f_string_dynamic_resize(0, &cache->name_file);
- f_string_dynamic_resize(0, &cache->name_item);
- f_string_dynamic_resize(0, &cache->generic);
- f_string_dynamic_resize(0, &cache->name_action);
- }
-#endif // _di_controller_cache_action_delete_simple_
-
-#ifndef _di_controller_cache_delete_simple_
- void controller_cache_delete_simple(controller_cache_t *cache) {
-
- macro_f_array_lengths_t_delete_simple(cache->ats)
- macro_f_array_lengths_t_delete_simple(cache->stack)
- macro_f_fss_delimits_t_delete_simple(cache->delimits)
-
- f_string_dynamic_resize(0, &cache->buffer_file);
- f_string_dynamic_resize(0, &cache->buffer_item);
- f_string_dynamic_resize(0, &cache->buffer_path);
-
- f_string_ranges_resize(0, &cache->comments);
- f_string_ranges_resize(0, &cache->content_action);
- f_string_ranges_resize(0, &cache->object_actions);
- f_string_ranges_resize(0, &cache->object_items);
-
- f_string_rangess_resize(0, &cache->content_actions);
- f_string_rangess_resize(0, &cache->content_items);
-
- controller_cache_action_delete_simple(&cache->action);
- }
-#endif // _di_controller_cache_delete_simple_
-
-#ifndef _di_controller_entry_action_delete_simple_
- void controller_entry_action_delete_simple(controller_entry_action_t *action) {
-
- f_string_dynamics_resize(0, &action->parameters);
- }
-#endif // _di_controller_entry_action_delete_simple_
-
-#ifndef _di_controller_entry_actions_delete_simple_
- void controller_entry_actions_delete_simple(controller_entry_actions_t *actions) {
-
- actions->used = actions->size;
-
- while (actions->used) {
- controller_entry_action_delete_simple(&actions->array[--actions->used]);
- } // while
-
- f_memory_delete(actions->size, sizeof(controller_entry_action_t), (void **) & actions->array);
- actions->size = 0;
- }
-#endif // _di_controller_entry_actions_delete_simple_
-
-#ifndef _di_controller_entry_actions_increase_by_
- f_status_t controller_entry_actions_increase_by(const f_array_length_t amount, controller_entry_actions_t *actions) {
-
- if (actions->used + amount > actions->size) {
- if (actions->used + amount > F_array_length_t_size_d) {
- return F_status_set_error(F_array_too_large);
- }
-
- const f_status_t status = f_memory_resize(actions->size, actions->used + amount, sizeof(controller_entry_action_t), (void **) & actions->array);
-
- if (F_status_is_error_not(status)) {
- actions->size = actions->used + amount;
- }
-
- return status;
- }
-
- return F_data_not;
- }
-#endif // _di_controller_entry_actions_increase_by_
-
-#ifndef _di_controller_entry_item_delete_simple_
- void controller_entry_item_delete_simple(controller_entry_item_t *item) {
-
- f_string_dynamic_resize(0, &item->name);
-
- controller_entry_actions_delete_simple(&item->actions);
- }
-#endif // _di_controller_entry_item_delete_simple_
-
-#ifndef _di_controller_entry_items_delete_simple_
- void controller_entry_items_delete_simple(controller_entry_items_t *items) {
-
- items->used = items->size;
-
- while (items->used) {
- controller_entry_item_delete_simple(&items->array[--items->used]);
- } // while
-
- f_memory_delete(items->size, sizeof(controller_entry_item_t), (void **) & items->array);
- items->size = 0;
- }
-#endif // _di_controller_entry_items_delete_simple_
-
-#ifndef _di_controller_entry_items_increase_by_
- f_status_t controller_entry_items_increase_by(const f_array_length_t amount, controller_entry_items_t *items) {
-
- if (items->used + amount > items->size) {
- if (items->used + amount > F_array_length_t_size_d) {
- return F_status_set_error(F_array_too_large);
- }
-
- const f_status_t status = f_memory_resize(items->size, items->used + amount, sizeof(controller_entry_item_t), (void **) & items->array);
-
- if (F_status_is_error_not(status)) {
- items->size = items->used + amount;
- }
-
- return status;
- }
-
- return F_data_not;
- }
-#endif // _di_controller_entry_items_increase_by_
-
-#ifndef _di_controller_lock_delete_mutex_
- void controller_lock_delete_mutex(f_thread_mutex_t *mutex) {
-
- const f_status_t status = f_thread_mutex_delete(mutex);
-
- if (F_status_is_error(status)) {
- if (F_status_set_fine(status) == F_busy) {
- if (f_thread_mutex_delete(mutex) == F_none) {
- mutex = 0;
- }
- }
- }
- else {
- mutex = 0;
- }
- }
-#endif // _di_controller_lock_delete_mutex_
-
-#ifndef _di_controller_lock_delete_rw_
- void controller_lock_delete_rw(f_thread_lock_t *lock) {
-
- const f_status_t status = f_thread_lock_delete(lock);
-
- if (F_status_is_error(status)) {
- if (F_status_set_fine(status) == F_busy) {
- if (f_thread_lock_delete(lock) == F_none) {
- lock = 0;
- }
- }
- }
- else {
- lock = 0;
- }
- }
-#endif // _di_controller_lock_delete_rw_
-
-#ifndef _di_controller_lock_delete_simple_
- void controller_lock_delete_simple(controller_lock_t *lock) {
-
- controller_lock_delete_mutex(&lock->print);
- controller_lock_delete_mutex(&lock->alert);
-
- controller_lock_delete_rw(&lock->process);
- controller_lock_delete_rw(&lock->rule);
-
- f_thread_condition_delete(&lock->alert_condition);
- }
-#endif // _di_controller_lock_delete_simple_
-
-#ifndef _di_controller_pids_increase_
- f_status_t controller_pids_increase(controller_pids_t *pids) {
-
- if (pids->used + 1 > pids->size) {
- f_array_length_t size = pids->used + controller_common_allocation_small_d;
-
- if (size > F_array_length_t_size_d) {
- if (pids->used + 1 > F_array_length_t_size_d) {
- return F_status_set_error(F_array_too_large);
- }
-
- size = F_array_length_t_size_d;
- }
-
- return controller_pids_resize(size, pids);
- }
-
- return F_data_not;
- }
-#endif // _di_controller_pids_increase_
-
-#ifndef _di_controller_pids_resize_
- f_status_t controller_pids_resize(const f_array_length_t length, controller_pids_t *pids) {
-
- f_status_t status = F_none;
-
- status = f_memory_resize(pids->size, length, sizeof(controller_rule_t), (void **) & pids->array);
-
- if (F_status_is_error_not(status)) {
- pids->size = length;
-
- if (pids->used > pids->size) {
- pids->used = length;
- }
- }
-
- return status;
- }
-#endif // _di_controller_pids_resize_
-
-#ifndef _di_controller_process_delete_simple_
- void controller_process_delete_simple(controller_process_t *process) {
-
- if (process->id_thread) {
- f_thread_signal(process->id_thread, F_signal_kill);
- f_thread_join(process->id_thread, 0);
-
- process->id_thread = 0;
- }
-
- f_thread_condition_delete(&process->wait);
-
- controller_lock_delete_rw(&process->lock);
- controller_lock_delete_rw(&process->active);
- controller_lock_delete_mutex(&process->wait_lock);
-
- controller_cache_delete_simple(&process->cache);
- controller_pids_resize(0, &process->childs);
- controller_rule_delete_simple(&process->rule);
-
- f_string_dynamics_resize(0, &process->path_pids);
-
- macro_f_array_lengths_t_delete_simple(process->stack)
- }
-#endif // _di_controller_process_delete_simple_
-
-#ifndef _di_controller_processs_delete_simple_
- void controller_processs_delete_simple(controller_processs_t *processs) {
-
- controller_processs_resize(0, processs);
- }
-#endif // _di_controller_processs_delete_simple_
-
-#ifndef _di_controller_processs_increase_
- f_status_t controller_processs_increase(controller_processs_t *processs) {
-
- if (processs->used + 1 > processs->size) {
- f_array_length_t size = processs->used + controller_common_allocation_small_d;
-
- if (size > F_array_length_t_size_d) {
- if (processs->used + 1 > F_array_length_t_size_d) {
- return F_status_set_error(F_array_too_large);
- }
-
- size = F_array_length_t_size_d;
- }
-
- return controller_processs_resize(size, processs);
- }
-
- return F_data_not;
- }
-#endif // _di_controller_processs_increase_
-
-#ifndef _di_controller_processs_resize_
- f_status_t controller_processs_resize(const f_array_length_t length, controller_processs_t *processs) {
-
- f_status_t status = F_none;
-
- for (f_array_length_t i = length; i < processs->size; ++i) {
-
- if (processs->array[i]) {
- controller_process_delete_simple(processs->array[i]);
-
- f_memory_delete(1, sizeof(f_array_length_t *), (void **) & processs->array[i]);
- }
- } // for
-
- status = f_memory_resize(processs->size, length, sizeof(controller_process_t), (void **) & processs->array);
-
- if (F_status_is_error_not(status) && length) {
-
- controller_process_t *process = 0;
-
- // the lock must be initialized, but only once, so initialize immediately upon allocation.
- for (; processs->size < length; ++processs->size) {
-
- status = f_memory_new(1, sizeof(controller_process_t), (void **) &processs->array[processs->size]);
-
- if (F_status_is_error_not(status)) {
- process = processs->array[processs->size];
-
- status = f_thread_lock_create(0, &process->lock);
- }
-
- if (F_status_is_error_not(status)) {
- status = f_thread_lock_create(0, &process->active);
- }
-
- if (F_status_is_error_not(status)) {
- status = f_thread_condition_create(0, &process->wait);
- }
-
- if (F_status_is_error_not(status)) {
- status = f_thread_mutex_create(0, &process->wait_lock);
- }
-
- if (F_status_is_error(status)) {
- processs->size = length;
-
- return status;
- }
- else {
- for (f_array_length_t i = 0; i < controller_rule_action_type__enum_size_e; ++i) {
- process->rule.status[i] = F_known_not;
- } // for
- }
- } // for
-
- processs->size = length;
-
- if (processs->used > processs->size) {
- processs->used = length;
- }
- }
-
- return status;
- }
-#endif // _di_controller_processs_resize_
-
-#ifndef _di_controller_rule_action_delete_simple_
- void controller_rule_action_delete_simple(controller_rule_action_t *action) {
-
- f_string_dynamics_resize(0, &action->parameters);
- }
-#endif // _di_controller_rule_action_delete_simple_
-
-#ifndef _di_controller_rule_actions_delete_simple_
- void controller_rule_actions_delete_simple(controller_rule_actions_t *actions) {
-
- actions->used = actions->size;
-
- while (actions->used) {
- controller_rule_action_delete_simple(&actions->array[--actions->used]);
- } // while
-
- f_memory_delete(actions->size, sizeof(controller_rule_action_t), (void **) & actions->array);
- actions->size = 0;
- }
-#endif // _di_controller_rule_actions_delete_simple_
-
-#ifndef _di_controller_rule_actions_increase_by_
- f_status_t controller_rule_actions_increase_by(const f_array_length_t amount, controller_rule_actions_t *actions) {
-
- if (actions->used + amount > actions->size) {
- if (actions->used + amount > F_array_length_t_size_d) {
- return F_status_set_error(F_array_too_large);
- }
-
- const f_status_t status = f_memory_resize(actions->size, actions->used + amount, sizeof(controller_rule_action_t), (void **) & actions->array);
-
- if (F_status_is_error_not(status)) {
- actions->size = actions->used + amount;
- }
-
- return status;
- }
-
- return F_data_not;
- }
-#endif // _di_controller_rule_actions_increase_by_
-
-#ifndef _di_controller_rule_delete_simple_
- void controller_rule_delete_simple(controller_rule_t * const rule) {
-
- f_string_dynamic_resize(0, &rule->alias);
- f_string_dynamic_resize(0, &rule->name);
- f_string_dynamic_resize(0, &rule->path);
- f_string_dynamic_resize(0, &rule->script);
-
- f_string_maps_resize(0, &rule->define);
- f_string_maps_resize(0, &rule->parameter);
-
- f_string_dynamics_resize(0, &rule->environment);
-
- macro_f_int32s_t_delete_simple(rule->affinity)
- macro_f_control_group_t_delete_simple(rule->control_group)
- macro_f_int32s_t_delete_simple(rule->groups)
- macro_f_limit_sets_t_delete_simple(rule->limits)
-
- if (rule->capability) {
- f_capability_delete(&rule->capability);
- }
-
- controller_rule_ons_delete_simple(&rule->ons);
- controller_rule_items_delete_simple(&rule->items);
- }
-#endif // _di_controller_rule_delete_simple_
-
-#ifndef _di_controller_rule_item_delete_simple_
- void controller_rule_item_delete_simple(controller_rule_item_t *item) {
-
- f_string_dynamic_resize(0, &item->pid_file);
-
- controller_rule_actions_delete_simple(&item->actions);
- }
-#endif // _di_controller_rule_item_delete_simple_
-
-#ifndef _di_controller_rule_items_delete_simple_
- void controller_rule_items_delete_simple(controller_rule_items_t *items) {
-
- items->used = items->size;
-
- while (items->used) {
- controller_rule_item_delete_simple(&items->array[--items->used]);
- } // while
-
- f_memory_delete(items->size, sizeof(controller_rule_item_t), (void **) & items->array);
- items->size = 0;
- }
-#endif // _di_controller_rule_items_delete_simple_
-
-#ifndef _di_controller_rule_on_delete_simple_
- void controller_rule_on_delete_simple(controller_rule_on_t *on) {
-
- f_string_dynamics_resize(0, &on->need);
- f_string_dynamics_resize(0, &on->want);
- f_string_dynamics_resize(0, &on->wish);
- }
-#endif // _di_controller_rule_on_delete_simple_
-
-#ifndef _di_controller_rule_ons_delete_simple_
- void controller_rule_ons_delete_simple(controller_rule_ons_t *ons) {
-
- ons->used = ons->size;
-
- while (ons->used) {
- controller_rule_on_delete_simple(&ons->array[--ons->used]);
- } // while
-
- f_memory_delete(ons->size, sizeof(controller_rule_on_t), (void **) & ons->array);
- ons->size = 0;
- }
-#endif // _di_controller_rule_ons_delete_simple_
-
-#ifndef _di_controller_rule_ons_increase_
- f_status_t controller_rule_ons_increase(controller_rule_ons_t *ons) {
-
- if (ons->used + 1 > ons->size) {
- f_array_length_t size = ons->used + controller_common_allocation_small_d;
-
- if (size > F_array_length_t_size_d) {
- if (ons->used + 1 > F_array_length_t_size_d) {
- return F_status_set_error(F_array_too_large);
- }
-
- size = F_array_length_t_size_d;
- }
-
- return controller_rule_ons_resize(size, ons);
- }
-
- return F_data_not;
- }
-#endif // _di_controller_rule_ons_increase_
-
-#ifndef _di_controller_rule_ons_resize_
- f_status_t controller_rule_ons_resize(const f_array_length_t length, controller_rule_ons_t *ons) {
-
- f_status_t status = F_none;
-
- for (f_array_length_t i = length; i < ons->size; ++i) {
- controller_rule_on_delete_simple(&ons->array[i]);
- } // for
-
- status = f_memory_resize(ons->size, length, sizeof(controller_rule_on_t), (void **) & ons->array);
-
- if (F_status_is_error_not(status)) {
- ons->size = length;
-
- if (ons->used > ons->size) {
- ons->used = length;
- }
- }
-
- return status;
- }
-#endif // _di_controller_rule_ons_resize_
-
-#ifndef _di_controller_rules_delete_simple_
- void controller_rules_delete_simple(controller_rules_t *rules) {
-
- controller_rules_resize(0, rules);
- }
-#endif // _di_controller_rules_delete_simple_
-
-#ifndef _di_controller_rules_increase_
- f_status_t controller_rules_increase(controller_rules_t *rules) {
-
- if (rules->used + 1 > rules->size) {
- f_array_length_t size = rules->used + controller_common_allocation_small_d;
-
- if (size > F_array_length_t_size_d) {
- if (rules->used + 1 > F_array_length_t_size_d) {
- return F_status_set_error(F_array_too_large);
- }
-
- size = F_array_length_t_size_d;
- }
-
- return controller_rules_resize(size, rules);
- }
-
- return F_data_not;
- }
-#endif // _di_controller_rules_increase_
-
-#ifndef _di_controller_rules_resize_
- f_status_t controller_rules_resize(const f_array_length_t length, controller_rules_t *rules) {
-
- f_status_t status = F_none;
-
- for (f_array_length_t i = length; i < rules->size; ++i) {
- controller_rule_delete_simple(&rules->array[i]);
- } // for
-
- status = f_memory_resize(rules->size, length, sizeof(controller_rule_t), (void **) & rules->array);
-
- if (F_status_is_error_not(status)) {
- rules->size = length;
-
- if (rules->used > rules->size) {
- rules->used = length;
- }
- }
-
- return status;
- }
-#endif // _di_controller_rules_resize_
-
-#ifndef _di_controller_setting_delete_simple_
- void controller_setting_delete_simple(controller_setting_t *setting) {
-
- f_string_dynamic_resize(0, &setting->path_control);
- f_string_dynamic_resize(0, &setting->path_pid);
- f_string_dynamic_resize(0, &setting->path_setting);
-
- f_string_dynamic_resize(0, &setting->name_entry);
-
- controller_entry_items_delete_simple(&setting->entry.items);
- controller_entry_items_delete_simple(&setting->exit.items);
- controller_rules_delete_simple(&setting->rules);
- }
-#endif // _di_controller_setting_delete_simple_
-
-#ifndef _di_controller_thread_delete_simple_
- void controller_thread_delete_simple(controller_thread_t *thread) {
-
- controller_lock_delete_simple(&thread->lock);
- controller_processs_resize(0, &thread->processs);
- controller_cache_delete_simple(&thread->cache);
- }
-#endif // _di_controller_thread_delete_simple_
-
#ifdef __cplusplus
} // extern "C"
#endif
extern "C" {
#endif
+// These are included in the order of their dependencies.
+#include "common/private-cache.h"
+#include "common/private-execute_set.h"
+#include "common/private-lock.h"
+#include "common/private-rule.h"
+#include "common/private-task.h"
+#include "common/private-process.h"
+#include "common/private-entry.h"
+#include "common/private-setting.h"
+#include "common/private-thread.h"
+#include "common/private-state.h"
+
/**
* All special strings used within this program.
*
#define CONTROLLER_bash_s "bash"
#define CONTROLLER_batch_s "batch"
#define CONTROLLER_capability_s "capability"
+ #define CONTROLLER_cgroup_s "cgroup"
#define CONTROLLER_create_s "create"
#define CONTROLLER_command_s "command"
#define CONTROLLER_consider_s "consider"
#define CONTROLLER_control_s "control"
#define CONTROLLER_control_group_s "control_group"
+ #define CONTROLLER_control_mode_s "control_mode"
+ #define CONTROLLER_control_user_s "control_user"
#define CONTROLLER_cpu_s "cpu"
#define CONTROLLER_core_s "core"
#define CONTROLLER_data_s "data"
#define controller_bash_s_length 4
#define controller_batch_s_length 5
#define controller_capability_s_length 10
+ #define controller_cgroup_s_length 6
#define controller_create_s_length 6
#define controller_command_s_length 7
#define controller_consider_s_length 8
#define controller_control_s_length 7
#define controller_control_group_s_length 13
+ #define controller_control_mode_s_length 12
+ #define controller_control_user_s_length 12
#define controller_core_s_length 4
#define controller_cpu_s_length 3
#define controller_data_s_length 4
extern const f_string_t controller_bash_s;
extern const f_string_t controller_batch_s;
extern const f_string_t controller_capability_s;
+ extern const f_string_t controller_cgroup_s;
extern const f_string_t controller_create_s;
extern const f_string_t controller_command_s;
extern const f_string_t controller_consider_s;
extern const f_string_t controller_control_s;
extern const f_string_t controller_control_group_s;
+ extern const f_string_t controller_control_mode_s;
+ extern const f_string_t controller_control_user_s;
extern const f_string_t controller_core_s;
extern const f_string_t controller_cpu_s;
extern const f_string_t controller_data_s;
#endif // _di_controller_common_
/**
- * Action related cache.
- *
- * line_action: The line in some file representing an Action.
- * line_item: The line in some file representing an Item.
- * name_action: A NULL terminated name of some Action.
- * name_file: A NULL terminated name of some File.
- * name_item: A NULL terminated name of some Item.
- * generic: A NULL terminated string for general use.
- */
-#ifndef _di_controller_cache_action_t_
- typedef struct {
- f_array_length_t line_action;
- f_array_length_t line_item;
-
- f_string_dynamic_t name_action;
- f_string_dynamic_t name_file;
- f_string_dynamic_t name_item;
-
- f_string_dynamic_t generic;
- } controller_cache_action_t;
-
- #define controller_cache_action_t_initialize { \
- 0, \
- 0, \
- f_string_dynamic_t_initialize, \
- f_string_dynamic_t_initialize, \
- f_string_dynamic_t_initialize, \
- f_string_dynamic_t_initialize, \
- }
-
- #define macro_controller_cache_action_t_clear(cache) \
- cache.line_action = 0; \
- cache.line_item = 0; \
- macro_f_string_dynamic_t_clear(cache.name_action) \
- macro_f_string_dynamic_t_clear(cache.name_file) \
- macro_f_string_dynamic_t_clear(cache.name_item) \
- macro_f_string_dynamic_t_clear(cache.generic)
-#endif // _di_controller_cache_action_t_
-
-/**
- * A cache intended for re-using memory while loading and processing rules whenever possible.
- *
- * timestamp: The timestamp.
- * range_action: The Range for some Action.
- * ats: Locations.
- * stack: Locations within a items history used as a history stack for circular recursion prevention.
- * comments: Comments associated with a buffer string.
- * delimits: Delimits associated with a buffer string.
- * content_action: The specific Content for some Action.
- * content_actions: Content for some Action.
- * content_items: Content for some Item.
- * object_actions: Objects for some Action.
- * object_items: Objects for some Item.
- * buffer_file: A generic file related buffer.
- * buffer_item: A generic item related buffer.
- * buffer_path: A generic path related buffer.
- * action: A cache for some Action, often used by error printing for reporting where an error happened.
- */
-#ifndef _di_controller_cache_t_
- typedef struct {
- f_time_spec_t timestamp;
-
- f_string_range_t range_action;
-
- f_array_lengths_t ats;
- f_array_lengths_t stack;
-
- f_fss_comments_t comments;
- f_fss_delimits_t delimits;
-
- f_fss_content_t content_action;
- f_fss_contents_t content_actions;
- f_fss_contents_t content_items;
- f_fss_objects_t object_actions;
- f_fss_objects_t object_items;
-
- f_string_dynamic_t buffer_file;
- f_string_dynamic_t buffer_item;
- f_string_dynamic_t buffer_path;
-
- controller_cache_action_t action;
- } controller_cache_t;
-
- #define controller_cache_t_initialize { \
- f_time_spec_t_initialize, \
- f_string_range_t_initialize, \
- f_array_lengths_t_initialize, \
- f_array_lengths_t_initialize, \
- f_fss_comments_t_initialize, \
- f_fss_delimits_t_initialize, \
- f_fss_content_t_initialize, \
- f_fss_contents_t_initialize, \
- f_fss_contents_t_initialize, \
- f_fss_objects_t_initialize, \
- f_fss_objects_t_initialize, \
- f_string_dynamic_t_initialize, \
- f_string_dynamic_t_initialize, \
- f_string_dynamic_t_initialize, \
- controller_cache_action_t_initialize, \
- }
-#endif // _di_controller_cache_t_
-
-/**
- * A structure for passing execution arguments to the execute functions.
- *
- * parameter: All parameters sent to the program on execution.
- * as: All special properties to apply, such as cpu affinity.
- */
-#ifndef _di_controller_execute_set_t_
- typedef struct {
- fl_execute_parameter_t parameter;
- fl_execute_as_t as;
- } controller_execute_set_t;
-
- #define controller_execute_set_t_initialize { \
- fl_execute_parameter_t_initialize, \
- fl_execute_as_t_initialize \
- }
-
- #define macro_controller_execute_set_t_initialize(option, wait, environment, signals, main, as) { \
- macro_fl_execute_parameter_t_initialize(option, wait, environment, signals, main), \
- as, \
- }
-#endif // _di_controller_execute_set_t_
-
-/**
- * A structure for sharing mutexes globally between different threads.
- *
- * The print lock is intended to lock any activity printing to stdout/stderr.
- * The alert lock is intended for a generic waiting on alerts operations.
- * The process lock is intended to lock any activity on the processs structure.
- * The rule lock is intended to lock any activity on the rules structure.
- *
- * print: The print mutex lock.
- * alert: The alert mutex lock for waking up on alerts.
- * process: The process r/w lock.
- * rule: The rule r/w lock.
- * alert_condition: The condition used to trigger alerts.
- */
-#ifndef _di_controller_lock_t_
- typedef struct {
- f_thread_mutex_t print;
- f_thread_mutex_t alert;
-
- f_thread_lock_t process;
- f_thread_lock_t rule;
-
- f_thread_condition_t alert_condition;
- } controller_lock_t;
-
- #define controller_lock_t_initialize { \
- f_thread_mutex_t_initialize, \
- f_thread_mutex_t_initialize, \
- f_thread_lock_t_initialize, \
- f_thread_lock_t_initialize, \
- f_thread_condition_t_initialize, \
- }
-#endif // _di_controller_mutex_t_
-
-/**
- * The Rule "rerun" item for controlling re-execution.
- *
- * count: A count of the number of executions.
- * delay: The time to wait before attempting to re-run.
- * max: The maximum number of times to re-run (with 0 representing re-run infinitely) for executions.
- */
-#ifndef _di_controller_rule_rerun_item_t_
- typedef struct {
- bool reset;
-
- f_number_unsigned_t count;
- f_number_unsigned_t delay;
- f_number_unsigned_t max;
- } controller_rule_rerun_item_t;
-
- #define controller_rule_rerun_item_initialize { \
- F_false, \
- 0, \
- 5000, \
- 0, \
- }
-#endif // _di_controller_rule_rerun_item_t_
-
-/**
- * The Rule "rerun" values for controlling re-execution.
- *
- * controller_rule_rerun_is_*:
- * - failure: The success re-run is enabled.
- * - failure_reset: Reset success counter when failure is returned.
- * - success: The success re-run is enabled.
- * - success_reset: Reset failure counter when success is returned.
- *
- * is: A bitwise set of options to designate whether rerun is enabled or not and other options.
- * count_failure: A count of the number of failed executions.
- * count_success: A count of the number of successful executions.
- * delay_failure: The time to wait before attempting to "rerun" for failed executions.
- * delay_success: The time to wait before attempting to "rerun" for successful executions.
- * max_failure: The maximum number of times to "rerun" (with 0 representing "rerun" infinitely) for failed executions.
- * max_success: The maximum number of times to "rerun" (with 0 representing "rerun" infinitely) for successful executions.
- */
-#ifndef _di_controller_rule_rerun_t_
- #define controller_rule_rerun_is_failure_d 0x1
- #define controller_rule_rerun_is_failure_reset_d 0x2
- #define controller_rule_rerun_is_success_d 0x4
- #define controller_rule_rerun_is_success_reset_d 0x8
-
- typedef struct {
- uint8_t is;
-
- controller_rule_rerun_item_t failure;
- controller_rule_rerun_item_t success;
- } controller_rule_rerun_t;
-
- #define controller_rule_rerun_initialize { \
- 0, \
- controller_rule_rerun_item_initialize, \
- controller_rule_rerun_item_initialize, \
- }
-#endif // _di_controller_rule_rerun_t_
-
-/**
- * A Rule Action.
- *
- * controller_rule_action_method_*:
- * - extended: Designate that this Action is represented using FSS Extended.
- * - extended_list: Designate that this Action is represented using FSS Extended List.
- *
- * controller_rule_action_type_*:
- * - freeze: The Freeze execution instructions.
- * - group: The Group setting.
- * - kill: The Kill execution instructions.
- * - pause: The Pause execution instructions.
- * - pid_file: The PID file setting.
- * - rerun: The Re-run execution after success or failure.
- * - reload: The Reload execution instructions.
- * - restart: The Restart execution instructions.
- * - resume: The Resume execution instructions.
- * - start: The Start execution instructions.
- * - stop: The Stop execution instructions.
- * - thaw: The Thaw execution instructions.
- * - user: The User setting.
- * - with: The With flags.
- *
- * type: The Rule Action type.
- * line: The line number where the Rule Action begins.
- * status: The last execution status of the Rule Action.
- * parameters: All parameters associated with the Rule Action.
- */
-#ifndef _di_controller_rule_action_t_
- #define controller_rule_action_method_string_extended_s "FSS-0001 (Extended)"
- #define controller_rule_action_method_string_extended_list_s "FSS-0003 (Extended List)"
-
- #define controller_rule_action_method_string_extended_s_length 19
- #define controller_rule_action_method_string_extended_list_s_length 24
-
- enum {
- controller_rule_action_method_extended_e = 1,
- controller_rule_action_method_extended_list_e,
- };
-
- enum {
- controller_rule_action_type_freeze_e = 1,
- controller_rule_action_type_group_e,
- controller_rule_action_type_kill_e,
- controller_rule_action_type_pause_e,
- controller_rule_action_type_pid_file_e,
- controller_rule_action_type_reload_e,
- controller_rule_action_type_rerun_e,
- controller_rule_action_type_restart_e,
- controller_rule_action_type_resume_e,
- controller_rule_action_type_start_e,
- controller_rule_action_type_stop_e,
- controller_rule_action_type_thaw_e,
- controller_rule_action_type_user_e,
- controller_rule_action_type_with_e,
-
- // designate the largest value in the enum, the '__' is intended.
- controller_rule_action_type__enum_size_e,
- };
-
- // Execute type starts at 0 because it is intended to be used as an index within a static array.
- enum {
- controller_rule_action_type_execute_freeze_e = 0,
- controller_rule_action_type_execute_kill_e,
- controller_rule_action_type_execute_pause_e,
- controller_rule_action_type_execute_reload_e,
- controller_rule_action_type_execute_restart_e,
- controller_rule_action_type_execute_resume_e,
- controller_rule_action_type_execute_start_e,
- controller_rule_action_type_execute_stop_e,
- controller_rule_action_type_execute_thaw_e,
-
- // designate the largest value in the enum, the '__' is intended.
- controller_rule_action_type_execute__enum_size_e,
- };
-
- typedef struct {
- uint8_t type;
- f_array_length_t line;
- f_status_t status;
-
- f_string_dynamics_t parameters;
- } controller_rule_action_t;
-
- #define controller_rule_action_t_initialize { \
- 0, \
- 0, \
- F_known_not, \
- f_string_dynamics_t_initialize, \
- }
-#endif // _di_controller_rule_action_t_
-
-/**
- * The Rule Actions.
- *
- * array: An array of Rule Actions.
- * size: Total amount of allocated space.
- * used: Total number of allocated spaces used.
- */
-#ifndef _di_controller_rule_actions_t_
- typedef struct {
- controller_rule_action_t *array;
-
- f_array_length_t size;
- f_array_length_t used;
- } controller_rule_actions_t;
-
- #define controller_rule_actions_t_initialize { \
- 0, \
- 0, \
- 0, \
- }
-#endif // _di_controller_rule_actions_t_
-
-/**
- * A Rule Item.
- *
- * controller_rule_item_type_*:
- * - command: A Command to execute.
- * - script: A Script to execute.
- * - service: A Service to execute.
- * - setting: Settings associated with the Rule Item.
- * - utility: A Utility to execute.
- *
- * type: The type of the Rule Item.
- * with: A bitwise number representing execute "with" options.
- * line: The line number where the Rule Item begins.
- * reruns: An array designating rerun settings for each execution type available.
- * actions: The actions associated with the Rule Item.
- */
-#ifndef _di_controller_rule_item_t_
- enum {
- controller_rule_item_type_command_e = 1,
- controller_rule_item_type_script_e,
- controller_rule_item_type_service_e,
- controller_rule_item_type_setting_e,
- controller_rule_item_type_utility_e,
- };
-
- typedef struct {
- uint8_t type;
- uint8_t with;
- f_array_length_t line;
-
- f_string_dynamic_t pid_file;
- controller_rule_rerun_t reruns[controller_rule_action_type_execute__enum_size_e];
- controller_rule_actions_t actions;
- } controller_rule_item_t;
-
- #define controller_rule_item_t_initialize \
- { \
- 0, \
- 0, \
- 0, \
- f_string_dynamic_t_initialize, \
- { \
- controller_rule_rerun_t_initialize, \
- controller_rule_rerun_t_initialize, \
- controller_rule_rerun_t_initialize, \
- controller_rule_rerun_t_initialize, \
- controller_rule_rerun_t_initialize, \
- controller_rule_rerun_t_initialize, \
- controller_rule_rerun_t_initialize, \
- controller_rule_rerun_t_initialize, \
- controller_rule_rerun_t_initialize, \
- }, \
- controller_rule_actions_t_initialize, \
- }
-#endif // _di_controller_rule_item_t_
-
-/**
- * The Rule Items.
- *
- * array: An array of Rule Items.
- * size: Total amount of allocated space.
- * used: Total number of allocated spaces used.
- */
-#ifndef _di_controller_rule_items_t_
- typedef struct {
- controller_rule_item_t *array;
-
- f_array_length_t size;
- f_array_length_t used;
- } controller_rule_items_t;
-
- #define controller_rule_items_initialize { \
- 0, \
- 0, \
- 0, \
- }
-#endif // _di_controller_rule_items_t_
-
-/**
- * The Rule "on" values for designating dependencies.
- *
- * action: The Rule Action type this "on" dependencies are associated with.
- * need: The Rule Alias for a required Rule.
- * want: The Rule Alias for an optional Rule that is required to succeed if found.
- * wish: The Rule Alias for an optional Rule that is not required.
- */
-#ifndef _di_controller_rule_on_t_
- typedef struct {
- uint8_t action;
-
- f_string_dynamics_t need;
- f_string_dynamics_t want;
- f_string_dynamics_t wish;
- } controller_rule_on_t;
-
- #define controller_rule_on_initialize { \
- 0, \
- f_string_dynamics_t_initialize, \
- f_string_dynamics_t_initialize, \
- f_string_dynamics_t_initialize, \
- }
-#endif // _di_controller_rule_on_t_
-
-/**
- * The Rule "on" array.
- *
- * array: An array of Rule "on" values.
- * size: Total amount of allocated space.
- * used: Total number of allocated spaces used.
- */
-#ifndef _di_controller_rule_ons_t_
- typedef struct {
- controller_rule_on_t *array;
-
- f_array_length_t size;
- f_array_length_t used;
- } controller_rule_ons_t;
-
- #define controller_rule_ons_t_initialize { \
- 0, \
- 0, \
- 0, \
- }
-#endif // _di_controller_rule_ons_t_
-
-/**
- * A Rule.
- *
- * controller_rule_setting_type_*:
- * - affinity: Setting type representing a affinity.
- * - capability: Setting type representing a capability.
- * - control_group: Setting type representing a control group.
- * - define: Setting type representing a define.
- * - environment: Setting type representing a environment.
- * - group: Setting type representing a group.
- * - limit: Setting type representing a limit.
- * - name: Setting type representing a name.
- * - nice: Setting type representing a nice.
- * - on: Setting type representing a on.
- * - parameter: Setting type representing a parameter.
- * - path: Setting type representing a path.
- * - scheduler: Setting type representing a scheduler.
- * - script: Setting type representing a script.
- * - user: Setting type representing a user.
- *
- * controller_rule_has_*:
- * - control_group: Has type representing a control group.
- * - group: Has type representing a group.
- * - nice: Has type representing a nice.
- * - scheduler: Has type representing a scheduler.
- * - user: Has type representing a user.
- *
- * affinity: The cpu affinity to be used when executing the Rule.
- * alias: The distinct ID (machine name) of the rule, such as "service/ssh".
- * capability: The capability setting if the Rule "has" a capability.
- * control_group: The control group setting if the Rule "has" a control group.
- * define: Any defines (environment variables) made available to the Rule for IKI substitution or just as environment variables.
- * environment: All environment variables allowed to be exposed to the Rule when processing.
- * group: The group ID if the Rule "has" a group.
- * groups: A set of group IDs to run the process with (first specified group is the primary group).
- * has: Bitwise set of "has" codes representing what the Rule has.
- * items: All items associated with the Rule.
- * limits: The cpu/resource limits to use when executing the Rule.
- * name: A human name for the Rule (does not have to be distinct), such as "Bash Script".
- * nice: The niceness value if the Rule "has" nice.
- * on: A set of parameters for defining dependencies and how they are needed, wanted, or wished for.
- * parameter: Any parameters made available to the Rule for IKI substitution.
- * path: The path to the Rule file.
- * scheduler: The scheduler setting if the Rule "has" a scheduler.
- * script: The program or path to the program of the scripting engine to use when processing scripts in this Rule.
- * status: A set of action-specific success/failure status of the Rule. Each index represents a controller_rule_action_type_* enum value. Index 0 represents a global status.
- * timeout_kill: The timeout to wait relating to using a kill signal.
- * timeout_start: The timeout to wait relating to starting a process.
- * timeout_stop: The timeout to wait relating to stopping a process.
- * timestamp: The timestamp when the Rule was loaded.
- * user: The User ID if the Rule "has" a user.
- */
-#ifndef _di_controller_rule_t_
- enum {
- controller_rule_setting_type_affinity_e = 1,
- controller_rule_setting_type_capability_e,
- controller_rule_setting_type_control_group_e,
- controller_rule_setting_type_define_e,
- controller_rule_setting_type_environment_e,
- controller_rule_setting_type_group_e,
- controller_rule_setting_type_limit_e,
- controller_rule_setting_type_name_e,
- controller_rule_setting_type_nice_e,
- controller_rule_setting_type_on_e,
- controller_rule_setting_type_parameter_e,
- controller_rule_setting_type_path_e,
- controller_rule_setting_type_scheduler_e,
- controller_rule_setting_type_script_e,
- controller_rule_setting_type_timeout_e,
- controller_rule_setting_type_user_e,
- };
-
- // bitwise codes representing properties on controller_rule_t that have been found in the rule file.
- #define controller_rule_has_control_group_d 0x1
- #define controller_rule_has_environment_d 0x2
- #define controller_rule_has_group_d 0x4
- #define controller_rule_has_nice_d 0x8
- #define controller_rule_has_scheduler_d 0x10
- #define controller_rule_has_user_d 0x20
-
- // Designate codes for timeout settings to be used during the loading of the rule timeout settings.
- #define controller_rule_timeout_code_kill_d 1
- #define controller_rule_timeout_code_start_d 2
- #define controller_rule_timeout_code_stop_d 3
-
- typedef struct {
- f_status_t status[controller_rule_action_type__enum_size_e];
-
- f_number_unsigned_t timeout_kill;
- f_number_unsigned_t timeout_start;
- f_number_unsigned_t timeout_stop;
-
- uint8_t has;
- int nice;
- uid_t user;
- gid_t group;
-
- f_time_spec_t timestamp;
-
- f_string_dynamic_t alias;
- f_string_dynamic_t name;
- f_string_dynamic_t path;
- f_string_dynamic_t script;
-
- f_string_maps_t define;
- f_string_maps_t parameter;
-
- f_string_dynamics_t environment;
-
- f_int32s_t affinity;
- f_capability_t capability;
- f_control_group_t control_group;
- f_int32s_t groups;
- f_limit_sets_t limits;
- f_execute_scheduler_t scheduler;
-
- controller_rule_ons_t ons;
- controller_rule_items_t items;
- } controller_rule_t;
-
- #define controller_rule_t_initialize { \
- { \
- F_known_not, \
- F_known_not, \
- F_known_not, \
- F_known_not, \
- F_known_not, \
- F_known_not, \
- F_known_not, \
- F_known_not, \
- F_known_not, \
- F_known_not, \
- F_known_not, \
- F_known_not, \
- F_known_not, \
- F_known_not, \
- F_known_not, \
- }, \
- 0, \
- 0, \
- 0, \
- 0, \
- 0, \
- 0, \
- 0, \
- f_time_spec_t_initialize, \
- f_string_dynamic_t_initialize, \
- f_string_dynamic_t_initialize, \
- f_string_dynamic_t_initialize, \
- f_string_dynamic_t_initialize, \
- f_string_maps_t_initialize, \
- f_string_maps_t_initialize, \
- f_string_dynamics_t_initialize, \
- f_int32s_t_initialize, \
- f_capability_t_initialize, \
- f_control_group_t_initialize, \
- f_int32s_t_initialize, \
- f_limit_sets_t_initialize, \
- f_execute_scheduler_t_initialize, \
- controller_rule_ons_initialize, \
- controller_rule_items_initialize, \
- }
-#endif // _di_controller_rule_t_
-
-/**
- * The Rules.
- *
- * array: An array of Rules.
- * size: Total amount of allocated space.
- * used: Total number of allocated spaces used.
- */
-#ifndef _di_controller_rules_t_
- typedef struct {
- controller_rule_t *array;
-
- f_array_length_t size;
- f_array_length_t used;
- } controller_rules_t;
-
- #define controller_rules_t_initialize { \
- 0, \
- 0, \
- 0, \
- }
-#endif // _di_controller_rules_t_
-
-/**
* A set of codes representing different with flags.
*/
#ifndef _di_controller_with_defines_
#endif // _di_controller_with_defines_
/**
- * An array of PIDs.
- *
- * array: An array of rule PIDs.
- * size: Total amount of allocated space.
- * used: Total number of allocated spaces used.
- */
-#ifndef _di_controller_pids_t_
- typedef struct {
- pid_t *array;
-
- f_array_length_t size;
- f_array_length_t used;
- } controller_pids_t;
-
- #define controller_pids_t_initialize { \
- 0, \
- 0, \
- 0, \
- }
-#endif // _di_controller_pids_t_
-
-/**
- * A Rule Process.
- *
- * This refers to "process" as in the processing of a single rule for the given Rule ID and does not refer to "process" as in a CPU Process.
- *
- * The "cache" should only be used by the function processing/executing the process and as such should not require a write lock on the "process".
- * There should only be a single thread running any given Rule process at a time, guaranteeing the cache to not need read/write locks.
- *
- * Process States:
- * - idle: No process is running for this rule.
- * - busy: A process is actively using this, and is running synchronously.
- * - active: A process is actively using this, and is running asynchronously.
- * - done: A process has finished running on this and there is a thread that needs to be cleaned up.
- *
- * Process Types:
- * - entry: The process is started from an entry.
- * - exit: The process is started from an exit.
- * - control: The process is started from a control operation.
- *
- * id: The ID of this process relative to the processes array.
- * result: The last return code from an execution of a process.
- * status: The last execution status of the process.
- * state: The state of the process.
- * action: The action being performed.
- * options: Configuration options for this asynchronous thread.
- * child: The process id of a child process, if one is running (when forking to execute a child process).
- * id_thread: The thread id, a valid ID when state is "active", and an invalid ID when the state is "busy".
- * lock: A read/write lock on the structure.
- * active: A read/write lock representing that something is currently using this (read locks = in use, write lock = begin deleting).
- * wait: A thread condition to tell a process waiting process that the rule has is done being processed.
- * wait_lock: A mutex lock for working with "wait".
- * cache: The cache used in this process.
- * stack: A stack used to represent dependencies as Rule ID's to avoid circular rule dependencies (If Rule A waits on Rule B, then Rule B must not wait on Rule A).
- * rule: A copy of the rule actively being executed.
- * main_data: Used for passing the controller_main_t data to the process thread (to populate controller_global_t).
- * main_setting: Used for passing the controller_setting_t data to the process thread (to populate controller_global_t).
- * main_thread: Used for passing the controller_thread_t data to the process thread (to populate controller_global_t).
- */
-#ifndef _di_controller_process_t_
- #define controller_process_option_asynchronous_d 0x1
- #define controller_process_option_require_d 0x2
- #define controller_process_option_simulate_d 0x4
- #define controller_process_option_validate_d 0x8
- #define controller_process_option_wait_d 0x10
-
- enum {
- controller_process_state_idle_e = 1,
- controller_process_state_busy_e,
- controller_process_state_active_e,
- controller_process_state_done_e,
- };
-
- enum {
- controller_process_type_entry_e = 1,
- controller_process_type_exit_e,
- controller_process_type_control_e,
- };
-
- typedef struct {
- f_array_length_t id;
-
- uint8_t state;
- uint8_t action;
- uint8_t options;
- uint8_t type;
-
- int result;
-
- f_thread_id_t id_thread;
- f_thread_lock_t lock;
- f_thread_lock_t active;
- f_thread_condition_t wait;
- f_thread_mutex_t wait_lock;
-
- controller_cache_t cache;
- f_array_lengths_t stack;
-
- f_string_dynamics_t path_pids;
-
- controller_pids_t childs;
- controller_rule_t rule;
-
- void *main_data;
- void *main_setting;
- void *main_thread;
- } controller_process_t;
-
- #define controller_process_t_initialize { \
- 0, \
- 0, \
- 0, \
- 0, \
- 0, \
- 0, \
- f_thread_id_t_initialize, \
- f_thread_lock_t_initialize, \
- f_thread_lock_t_initialize, \
- f_thread_condition_t_initialize, \
- controller_cache_t_initialize, \
- f_array_lengths_t_initialize, \
- f_string_dynamics_t_initialize, \
- controller_pids_t_initialize, \
- controller_rule_t_initialize, \
- 0, \
- 0, \
- 0, \
- }
-#endif // _di_controller_process_t_
-
-/**
- * The Rule Processes.
- *
- * Each process is a pointer of a process, to preserve memory locations that may ultimately change due to the resizing the array.
- *
- * array: An array of rule processes.
- * size: Total amount of allocated space.
- * used: Total number of allocated spaces used.
- */
-#ifndef _di_controller_processs_t_
- typedef struct {
- controller_process_t **array;
-
- f_array_length_t size;
- f_array_length_t used;
- } controller_processs_t;
-
- #define controller_processs_t_initialize { \
- 0, \
- 0, \
- 0, \
- }
-#endif // _di_controller_processs_t_
-
-/**
- * An Entry Item Action.
- *
- * controller_entry_action_type_*:
- * - consider: Designate a rule to be pre-loaded.
- * - execute: Execute into another program.
- * - failsafe: Designate a failsafe "item".
- * - freeze: A Rule Action for freezing.
- * - item: A named set of Rules.
- * - kill: A Rule Action for killing.
- * - pause: A Rule Action for pausing.
- * - ready: Designate readiness for special processing for Entry or Exit.
- * - reload: A Rule Action for reloading.
- * - restart: A Rule Action for restarting.
- * - resume: A Rule Action for resuming.
- * - start: A Rule Action for starting.
- * - stop: A Rule Action for stopping.
- * - timeout: Inline timeout settings.
- * - thaw: A Rule Action for unfreezing.
- *
- * controller_entry_rule_code_*:
- * - asynchronous: Process Rule asynchronously.
- * - require: Require Rule operations to succeed or the Entry/Exit will fail.
- * - wait: Wait for all existing asynchronous processes to finish before operating Rule.
- *
- * type: The type of Action.
- * code: A single code or sub-type associated with the Action.
- * line: The line number where the Entry Item begins.
- * number: The unsigned number that some types use instead of the "parameters".
- * status: The overall status.
- * parameters: The values associated with the Action.
- */
-#ifndef _di_controller_entry_action_t_
- enum {
- controller_entry_action_type_consider_e = 1,
- controller_entry_action_type_execute_e,
- controller_entry_action_type_failsafe_e,
- controller_entry_action_type_freeze_e,
- controller_entry_action_type_item_e,
- controller_entry_action_type_kill_e,
- controller_entry_action_type_pause_e,
- controller_entry_action_type_ready_e,
- controller_entry_action_type_reload_e,
- controller_entry_action_type_restart_e,
- controller_entry_action_type_resume_e,
- controller_entry_action_type_start_e,
- controller_entry_action_type_stop_e,
- controller_entry_action_type_timeout_e,
- controller_entry_action_type_thaw_e,
- };
-
- #define controller_entry_rule_code_asynchronous_d 0x1
- #define controller_entry_rule_code_require_d 0x2
- #define controller_entry_rule_code_wait_d 0x4
-
- #define controller_entry_timeout_code_kill_d 0x1
- #define controller_entry_timeout_code_start_d 0x2
- #define controller_entry_timeout_code_stop_d 0x4
-
- typedef struct {
- uint8_t type;
- uint8_t code;
-
- f_array_length_t line;
- f_number_unsigned_t number;
-
- f_status_t status;
-
- f_string_dynamics_t parameters;
- } controller_entry_action_t;
-
- #define controller_entry_action_t_initialize { \
- 0, \
- 0, \
- 0, \
- 0, \
- F_known_not, \
- f_string_dynamics_t_initialize, \
- }
-#endif // _di_controller_entry_action_t_
-
-/**
- * The Entry Item Actions.
- *
- * array: An array of Entry Item Actions.
- * size: Total amount of allocated space.
- * used: Total number of allocated spaces used.
- */
-#ifndef _di_controller_entry_actions_t_
- typedef struct {
- controller_entry_action_t *array;
-
- f_array_length_t size;
- f_array_length_t used;
- } controller_entry_actions_t;
-
- #define controller_entry_actions_t_initialize { \
- 0, \
- 0, \
- 0, \
- }
-#endif // _di_controller_entry_actions_t_
-
-/**
- * An Entry Item.
- *
- * line: The line number where the Entry Item begins.
- * name: The name of the Entry Item.
- * actions: The Actions associated with the Entry Item.
- */
-#ifndef _di_controller_entry_item_t_
- typedef struct {
- f_array_length_t line;
- f_string_dynamic_t name;
-
- controller_entry_actions_t actions;
- } controller_entry_item_t;
-
- #define controller_entry_item_t_initialize \
- { \
- 0, \
- f_string_dynamic_t_initialize, \
- controller_entry_actions_t_initialize, \
- }
-#endif // _di_controller_entry_item_t_
-
-/**
- * An Entry Items.
- *
- * array: An array of Entry Items.
- * size: Total amount of allocated space.
- * used: Total number of allocated spaces used.
- */
-#ifndef _di_controller_entry_items_t_
- typedef struct {
- controller_entry_item_t *array;
-
- f_array_length_t size;
- f_array_length_t used;
- } controller_entry_items_t;
-
- #define controller_entry_items_t_initialize { \
- 0, \
- 0, \
- 0, \
- }
-
- #define macro_controller_entry_items_t_clear(items) \
- items.array = 0; \
- items.size = 0; \
- items.used = 0;
-#endif // _di_controller_entry_items_t_
-
-/**
- * The Entry or Exit.
- *
- * Entry and Exit files are essentially the same structure with minor differences in settings and behavior.
- * The structure is identical and due to lacking any particularly good name to represent both "entry" or "exit", the name "entry" is being used for both.
- *
- * controller_entry_pid_*:
- * - disable: Do not check for or create a PID file to represent the entry execution.
- * - require: Check to see if the PID file exists for an entry at startup and then when "ready" create a pid file, display error on pid file already exists or on failure and then fail.
- * - ready: When "ready" create a pid file, display error on failure and then fail (does not check if PID file exists).
- *
- * controller_entry_show_*:
- * - normal: Do not print anything other than warnings and errors, but allow executed programs and scripts to output however they like.
- * - init: Print like an init program, printing status of entry and rules as they are being started, stopped, etc...
- *
- * controller_entry_session_*:
- * - none: No special session configuration specified, use built in defaults.
- * - new: Designate the default to use a new session, ignoring built in defaults (passing FL_execute_parameter_option_session_d to the execute functions).
- * - same: Designate the default to use a same session, ignoring built in defaults.
- *
- * status: The overall status.
- * pid: The PID file generation setting.
- * session: The default session settings (when NULL, no default is specified).
- * show: The show setting for controlling what to show when executing entry items and rules.
- * timeout_kill: The timeout to wait relating to using a kill signal.
- * timeout_start: The timeout to wait relating to starting a process.
- * timeout_stop: The timeout to wait relating to stopping a process.
- * items: The array of entry items.
- */
-#ifndef _di_controller_entry_t_
- enum {
- controller_entry_pid_disable_e = 0,
- controller_entry_pid_require_e,
- controller_entry_pid_ready_e,
- };
-
- enum {
- controller_entry_show_normal_e = 0,
- controller_entry_show_init_e,
- };
-
- enum {
- controller_entry_session_none_e = 0,
- controller_entry_session_new_e,
- controller_entry_session_same_e,
- };
-
- typedef struct {
- f_status_t status;
-
- uint8_t pid;
- uint8_t session;
- uint8_t show;
-
- f_number_unsigned_t timeout_kill;
- f_number_unsigned_t timeout_start;
- f_number_unsigned_t timeout_stop;
-
- controller_entry_items_t items;
- } controller_entry_t;
-
- #define controller_entry_t_initialize { \
- F_known_not, \
- controller_entry_pid_require_e, \
- controller_entry_session_none_e, \
- controller_entry_show_normal_e, \
- 0, \
- 0, \
- 0, \
- controller_entry_items_t_initialize, \
- }
-#endif // _di_controller_entry_t_
-
-/**
- * All setting data.
- *
- * controller_setting_ready_*:
- * - no: Entry/Exit is not ready.
- * - wait: Entry/Exit has "ready" somewhere in the file but is not yet ready.
- * - yes: Entry/Exit is now ready (Entry/Exit is still being processed).
- * - done: Entry/Exit is ready and processing is complete.
- * - fail: Entry/Exit processing failed.
- * - abort: Abort received before finished processing Entry/Exit.
- *
- * controller_setting_mode_*:
- * - program: Run as a program, exiting when finished prrocess entry (and any respective exit).
- * - service: Run as a service, listening for requests after processing entry.
- *
- * interruptible: TRUE if the program responds to interrupt signals, FALSE to block/ignore interrupt signals.
- * ready: State representing if the settings are all loaded and is ready to run program operations.
- * failsafe_enabled: TRUE if failsafe execution is enabled, FALSE otherwise.
- * failsafe_item_id: The Entry Item ID to execute when failsafe execution is enabled.
- * path_control: File path to the control socket.
- * path_pid: File path to the PID file.
- * path_setting: File path to the setting directory.
- * entry: The Entry settings.
- * rules: All rules and their respective settings.
- */
-#ifndef _di_controller_setting_t
- enum {
- controller_setting_ready_no_e = 0,
- controller_setting_ready_wait_e,
- controller_setting_ready_yes_e,
- controller_setting_ready_done_e,
- controller_setting_ready_fail_e,
- controller_setting_ready_abort_e,
- };
-
- enum {
- controller_setting_mode_service_e = 0,
- controller_setting_mode_program_e,
- };
-
- typedef struct {
- bool interruptible;
- bool pid_created;
- uint8_t ready;
- uint8_t mode;
-
- bool failsafe_enabled;
- f_array_length_t failsafe_item_id;
-
- f_string_dynamic_t path_control;
- f_string_dynamic_t path_pid;
- f_string_dynamic_t path_setting;
-
- f_string_dynamic_t name_entry;
-
- controller_entry_t entry;
- controller_entry_t exit;
- controller_rules_t rules;
- } controller_setting_t;
-
- #define controller_setting_t_initialize { \
- F_false, \
- F_false, \
- 0, \
- 0, \
- F_false, \
- 0, \
- f_string_dynamic_t_initialize, \
- f_string_dynamic_t_initialize, \
- f_string_dynamic_t_initialize, \
- f_string_dynamic_t_initialize, \
- controller_entry_t_initialize, \
- controller_entry_t_initialize, \
- controller_rules_t_initialize, \
- }
-#endif // _di_controller_setting_t
-
-/**
- * A structure for managing threads.
- *
- * This is essentially data shared globally between threads, about threads.
- *
- * The "enabled" and "signal" utilize the lock: lock.process.
- *
- * enabled: TRUE when threads are active, FALSE when inactive and the program is essentially shutting down, no new threads should be started when FALSE.
- * signal: The code of any signal received.
- * status: A status used by the main entry/rule processing thread for synchronous operations.
- * id_cleanup: The thread ID representing the Cleanup Process.
- * id_control: The thread ID representing the Control Process.
- * id_entry: The thread ID representing the Entry or Exit Process.
- * id_rule: The thread ID representing the Rule Process.
- * id_signal: The thread ID representing the Signal Process.
- * lock: A r/w lock for operating on this structure.
- * processs: All Rule Process thread data.
- * cache: A cache used by the main entry/rule processing thread for synchronous operations.
- */
-#ifndef _di_controller_thread_t_
- #define controller_thread_cleanup_interval_long_d 3600 // 1 hour in seconds.
- #define controller_thread_cleanup_interval_short_d 180 // 3 minutes in seconds.
- #define controller_thread_exit_process_cancel_wait_d 600000000 // 0.6 seconds in nanoseconds.
- #define controller_thread_exit_process_cancel_total_d 150 // 90 seconds in multiples of wait.
- #define controller_thread_simulation_timeout_d 200 // 0.2 seconds in milliseconds.
-
- #define controller_thread_signal_wait_timeout_seconds_d 70
- #define controller_thread_signal_wait_timeout_nanoseconds_d 0
-
- #define controller_thread_lock_read_timeout_seconds_d 3
- #define controller_thread_lock_read_timeout_nanoseconds_d 0
- #define controller_thread_lock_write_timeout_seconds_d 3
- #define controller_thread_lock_write_timeout_nanoseconds_d 0
-
- #define controller_thread_wait_timeout_1_before_d 4
- #define controller_thread_wait_timeout_2_before_d 12
- #define controller_thread_wait_timeout_3_before_d 28
-
- #define controller_thread_wait_timeout_1_seconds_d 0
- #define controller_thread_wait_timeout_1_nanoseconds_d 20000000 // 0.02 seconds in nanoseconds.
- #define controller_thread_wait_timeout_2_seconds_d 0
- #define controller_thread_wait_timeout_2_nanoseconds_d 200000000 // 0.2 seconds in nanoseconds.
- #define controller_thread_wait_timeout_3_seconds_d 2
- #define controller_thread_wait_timeout_3_nanoseconds_d 0
- #define controller_thread_wait_timeout_4_seconds_d 20
- #define controller_thread_wait_timeout_4_nanoseconds_d 0
-
- #define controller_thread_exit_ready_timeout_seconds_d 0
- #define controller_thread_exit_ready_timeout_nanoseconds_d 500000000 // 0.5 seconds in nanoseconds.
-
- /**
- * States for enabled, designating how to stop the process.
- *
- * controller_thread_*:
- * - enabled_not: The controller is no longer enabled, shut down and abort all work.
- * - enabled: The controller is operating normally.
- * - enabled_execute: The controller is executing another process, all running operations must terminate.
- * - enabled_exit: The controller is shutting down, only process exit rules.
- * - enabled_exit_execute: The controller is executing another process while in failsafe mode, all running operations must terminate.
- * - enabled_exit_ready: The controller is shutting down, only process exit rules, and now ready to send termination signals.
- *
- * controller_thread_cancel_*:
- * - signal: Cancellation is triggered by a signal.
- * - call: Cancellation is explicitly called.
- * - execute: Cancellation is explicitly called due to an "execute" Item Action, when not during Exit.
- * - exit: Cancellation is explicitly called during Exit.
- * - exit_execute: Cancellation is explicitly called due to an "execute" Item Action during Exit.
- */
- enum {
- controller_thread_enabled_not_e = 0,
- controller_thread_enabled_e,
- controller_thread_enabled_execute_e,
- controller_thread_enabled_exit_e,
- controller_thread_enabled_exit_execute_e,
- controller_thread_enabled_exit_ready_e,
- };
-
- enum {
- controller_thread_cancel_signal_e = 0,
- controller_thread_cancel_call_e,
- controller_thread_cancel_execute_e,
- controller_thread_cancel_exit_e,
- controller_thread_cancel_exit_execute_e,
- };
-
- typedef struct {
- uint8_t enabled;
- int signal;
- f_status_t status;
-
- f_thread_id_t id_cleanup;
- f_thread_id_t id_control;
- f_thread_id_t id_entry;
- f_thread_id_t id_rule;
- f_thread_id_t id_signal;
-
- controller_lock_t lock;
- controller_processs_t processs;
- controller_cache_t cache;
- } controller_thread_t;
-
- #define controller_thread_t_initialize { \
- controller_thread_enabled_e, \
- 0, \
- F_none, \
- f_thread_id_t_initialize, \
- f_thread_id_t_initialize, \
- f_thread_id_t_initialize, \
- f_thread_id_t_initialize, \
- f_thread_id_t_initialize, \
- controller_lock_t_initialize, \
- controller_processs_t_initialize, \
- controller_cache_t_initialize, \
- }
-#endif // _di_controller_thread_t_
-
-/**
- * A structure for passing data to the interrupt state function.
- *
- * is_normal: Boolean designating if this is operating in a normal state.
- * thread: The thread data.
- */
-#ifndef _di_controller_state_interrupt_t_
- typedef struct {
- bool is_normal;
- controller_thread_t *thread;
- } controller_state_interrupt_t;
-
- #define controller_state_interrupt_t_initialize { \
- F_true, \
- 0, \
- }
-
- #define macro_controller_state_interrupt_t_initialize(is_normal, thread) { \
- is_normal, \
- thread, \
- }
-#endif // _di_controller_state_interrupt_t_
-
-/**
* A wrapper used for passing a common set of all data, particularly for sharing between threads.
*
* main: The main program data.
}
#endif // _di_controller_main_entry_t_
-/**
- * Fully deallocate all memory for the given cache without caring about return status.
- *
- * @param cache
- * The cache to deallocate.
- *
- * @see f_string_dynamic_resize()
- */
-#ifndef _di_controller_cache_action_delete_simple_
- extern void controller_cache_action_delete_simple(controller_cache_action_t *cache) F_attribute_visibility_internal_d;
-#endif // _di_controller_cache_action_delete_simple_
-
-/**
- * Fully deallocate all memory for the given cache without caring about return status.
- *
- * @param cache
- * The cache to deallocate.
- *
- * @see macro_f_array_lengths_t_delete_simple()
- * @see macro_f_fss_delimits_t_delete_simple()
- *
- * @see controller_cache_action_delete_simple()
- * @see f_string_dynamic_resize()
- * @see f_string_ranges_resize()
- * @see f_string_rangess_resize()
- */
-#ifndef _di_controller_cache_delete_simple_
- extern void controller_cache_delete_simple(controller_cache_t *cache) F_attribute_visibility_internal_d;
-#endif // _di_controller_cache_delete_simple_
-
-/**
- * Fully deallocate all memory for the given entry action without caring about return status.
- *
- * @param action
- * The action to deallocate.
- *
- * @see f_string_dynamics_resize()
- */
-#ifndef _di_controller_entry_action_delete_simple_
- extern void controller_entry_action_delete_simple(controller_entry_action_t *action) F_attribute_visibility_internal_d;
-#endif // _di_controller_entry_action_delete_simple_
-
-/**
- * Fully deallocate all memory for the given entry actions without caring about return status.
- *
- * @param actions
- * The entry_actions to deallocate.
- *
- * @see controller_entry_action_delete_simple()
- * @see f_memory_delete()
- */
-#ifndef _di_controller_entry_actions_delete_simple_
- extern void controller_entry_actions_delete_simple(controller_entry_actions_t *actions) F_attribute_visibility_internal_d;
-#endif // _di_controller_entry_actions_delete_simple_
-
-/**
- * Increase the size of the entry item actions array by the specified amount, but only if necessary.
- *
- * This only increases size if the current used plus amount is greater than the currently allocated size.
- *
- * @param amount
- * A positive number representing how much to increase the size by.
- * @param actions
- * The entry item actions to resize.
- *
- * @return
- * F_none on success.
- * F_array_too_large (with error bit) if the resulting new size is bigger than the max array length.
- *
- * Errors (with error bit) from: f_memory_resize().
- *
- * @see f_memory_resize()
- */
-#ifndef _di_controller_entry_actions_increase_by_
- extern f_status_t controller_entry_actions_increase_by(const f_array_length_t amount, controller_entry_actions_t *actions) F_attribute_visibility_internal_d;
-#endif // _di_controller_entry_actions_increase_by_
-
-/**
- * Fully deallocate all memory for the given entry item without caring about return status.
- *
- * @param item
- * The item to deallocate.
- *
- * @see f_string_dynamic_resize()
- */
-#ifndef _di_controller_entry_item_delete_simple_
- extern void controller_entry_item_delete_simple(controller_entry_item_t *item) F_attribute_visibility_internal_d;
-#endif // _di_controller_entry_item_delete_simple_
-
-/**
- * Fully deallocate all memory for the given entry items without caring about return status.
- *
- * @param items
- * The entry_items to deallocate.
- *
- * @see controller_entry_item_delete_simple()
- * @see f_memory_delete()
- */
-#ifndef _di_controller_entry_items_delete_simple_
- extern void controller_entry_items_delete_simple(controller_entry_items_t *items) F_attribute_visibility_internal_d;
-#endif // _di_controller_entry_items_delete_simple_
-
-/**
- * Increase the size of the entry items array by the specified amount, but only if necessary.
- *
- * This only increases size if the current used plus amount is greater than the currently allocated size.
- *
- * @param amount
- * A positive number representing how much to increase the size by.
- * @param items
- * The entry items to resize.
- *
- * @return
- * F_none on success.
- * F_array_too_large (with error bit) if the resulting new size is bigger than the max array length.
- *
- * Errors (with error bit) from: f_memory_resize().
- *
- * @see f_memory_resize()
- */
-#ifndef _di_controller_entry_items_increase_by_
- extern f_status_t controller_entry_items_increase_by(const f_array_length_t amount, controller_entry_items_t *items) F_attribute_visibility_internal_d;
-#endif // _di_controller_entry_items_increase_by_
-
-/**
- * Delete the mutex lock and if the mutex lock is busy, forcibly unlock it and then delete it.
- *
- * @param mutex
- * The mutex lock to delete.
- * Will be set to NULLif delete succeeded.
- */
-#ifndef _di_controller_lock_delete_mutex_
- extern void controller_lock_delete_mutex(f_thread_mutex_t *mutex) F_attribute_visibility_internal_d;
-#endif // _di_controller_lock_delete_mutex_
-
-/**
- * Delete the r/w lock and if the r/w lock is busy, forcibly unlock it and then delete it.
- *
- * @param lock
- * The r/w lock to delete.
- * Will be set to NULL if delete succeeded.
- */
-#ifndef _di_controller_lock_delete_rw_
- extern void controller_lock_delete_rw(f_thread_lock_t *lock) F_attribute_visibility_internal_d;
-#endif // _di_controller_lock_delete_rw_
-
-/**
- * Fully deallocate all memory for the given lock without caring about return status.
- *
- * @param lock
- * The lock to deallocate.
- *
- * @see f_thread_lock_delete()
- * @see f_thread_mutex_delete()
- */
-#ifndef _di_controller_lock_delete_simple_
- extern void controller_lock_delete_simple(controller_lock_t *lock) F_attribute_visibility_internal_d;
-#endif // _di_controller_lock_delete_simple_
-
-/**
- * Increase the size of the pid array, but only if necessary.
- *
- * If the given length is too large for the buffer, then attempt to set max buffer size (F_array_length_t_size_d).
- * If already set to the maximum buffer size, then the resize will fail.
- *
- * @param pids
- * The pid array to resize.
- *
- * @return
- * F_none on success.
- * F_data_not on success, but there is no reason to increase size (used + controller_common_allocation_small_d <= size).
- *
- * F_array_too_large (with error bit) if the new array length is too large.
- * F_memory_not (with error bit) on out of memory.
- * F_parameter (with error bit) if a parameter is invalid.
- *
- * @see controller_pids_resize()
- */
-#ifndef _di_controller_pids_increase_
- extern f_status_t controller_pids_increase(controller_pids_t *pids) F_attribute_visibility_internal_d;
-#endif // _di_controller_rule_increase_
-
-/**
- * Resize the pid array.
- *
- * @param length
- * The new size to use.
- * @param pids
- * The pid array to resize.
- *
- * @return
- * F_none on success.
- *
- * F_memory_not (with error bit) on out of memory.
- * F_parameter (with error bit) if a parameter is invalid.
- *
- * @see f_memory_resize()
- */
-#ifndef _di_controller_pids_resize_
- extern f_status_t controller_pids_resize(const f_array_length_t length, controller_pids_t *pids) F_attribute_visibility_internal_d;
-#endif // _di_controller_pids_resize_
-
-/**
- * Fully deallocate all memory for the given process without caring about return status.
- *
- * @param process
- * The process to deallocate.
- *
- * @see f_string_dynamic_resize()
- * @see f_thread_condition_delete()
- * @see f_thread_mutex_delete()
- */
-#ifndef _di_controller_process_delete_simple_
- extern void controller_process_delete_simple(controller_process_t *process) F_attribute_visibility_internal_d;
-#endif // _di_controller_process_delete_simple_
-
-/**
- * Fully deallocate all memory for the given processs without caring about return status.
- *
- * @param processs
- * The process array to deallocate.
- *
- * @see controller_processs_resize()
- */
-#ifndef _di_controller_processs_delete_simple_
- extern void controller_processs_delete_simple(controller_processs_t *processs) F_attribute_visibility_internal_d;
-#endif // _di_controller_processs_delete_simple_
-
-/**
- * Increase the size of the rule array, but only if necessary.
- *
- * If the given length is too large for the buffer, then attempt to set max buffer size (F_array_length_t_size_d).
- * If already set to the maximum buffer size, then the resize will fail.
- *
- * @param processs
- * The process array to resize.
- *
- * @return
- * F_none on success.
- * F_data_not on success, but there is no reason to increase size (used + controller_common_allocation_small_d <= size).
- *
- * F_array_too_large (with error bit) if the new array length is too large.
- * F_memory_not (with error bit) on out of memory.
- * F_parameter (with error bit) if a parameter is invalid.
- *
- * @see controller_processs_resize()
- */
-#ifndef _di_controller_processs_increase_
- extern f_status_t controller_processs_increase(controller_processs_t *processs) F_attribute_visibility_internal_d;
-#endif // _di_controller_rule_increase_
-
-/**
- * Resize the rule array.
- *
- * @param length
- * The new size to use.
- * @param processs
- * The process array to resize.
- *
- * @return
- * F_none on success.
- *
- * Errors (with error bit) from: controller_process_delete_simple().
- * Errors (with error bit) from: f_memory_resize().
- * Errors (with error bit) from: f_thread_condition_create().
- * Errors (with error bit) from: f_thread_lock_create().
- *
- * @see controller_process_delete_simple()
- * @see f_memory_resize()
- * @see f_thread_condition_create()
- * @see f_thread_lock_create()
- */
-#ifndef _di_controller_processs_resize_
- extern f_status_t controller_processs_resize(const f_array_length_t length, controller_processs_t *processs) F_attribute_visibility_internal_d;
-#endif // _di_controller_processs_resize_
-
-/**
- * Fully deallocate all memory for the given rule action without caring about return status.
- *
- * @param action
- * The action to deallocate.
- *
- * @see f_string_dynamics_resize()
- */
-#ifndef _di_controller_rule_action_delete_simple_
- extern void controller_rule_action_delete_simple(controller_rule_action_t *action) F_attribute_visibility_internal_d;
-#endif // _di_controller_rule_action_delete_simple_
-
-/**
- * Fully deallocate all memory for the given rule actions without caring about return status.
- *
- * @param actions
- * The rule_actions to deallocate.
- *
- * @see controller_rule_action_delete_simple()
- * @see f_memory_delete()
- */
-#ifndef _di_controller_rule_actions_delete_simple_
- extern void controller_rule_actions_delete_simple(controller_rule_actions_t *actions) F_attribute_visibility_internal_d;
-#endif // _di_controller_rule_actions_delete_simple_
-
-/**
- * Increase the size of the rule actions array by the specified amount, but only if necessary.
- *
- * This only increases size if the current used plus amount is greater than the currently allocated size.
- *
- * @param amount
- * A positive number representing how much to increase the size by.
- * @param actions
- * The actions to resize.
- *
- * @return
- * F_none on success.
- * F_array_too_large (with error bit) if the resulting new size is bigger than the max array length.
- *
- * Errors (with error bit) from: f_memory_resize().
- */
-#ifndef _di_controller_rule_actions_increase_by_
- extern f_status_t controller_rule_actions_increase_by(const f_array_length_t amount, controller_rule_actions_t *actions) F_attribute_visibility_internal_d;
-#endif // _di_controller_rule_actions_increase_by_
-
-/**
- * Fully deallocate all memory for the given rule without caring about return status.
- *
- * @param rule
- * The rule to deallocate.
- *
- * @see macro_f_control_group_t_delete_simple()
- * @see macro_f_int32s_t_delete_simple()
- * @see macro_f_limit_sets_t_delete_simple()
- * @see macro_f_string_dynamics_t_delete_simple()
- * @see macro_f_string_maps_t_delete_simple()
- * @see macro_f_thread_condition_t_delete_simple()
- * @see macro_f_thread_mutex_t_delete_simple()
- *
- * @see controller_rule_items_delete_simple()
- * @see f_capability_delete()
- * @see f_string_dynamic_resize()
- */
-#ifndef _di_controller_rule_delete_simple_
- extern void controller_rule_delete_simple(controller_rule_t *rule) F_attribute_visibility_internal_d;
-#endif // _di_controller_rule_delete_simple_
-
-/**
- * Fully deallocate all memory for the given rule item without caring about return status.
- *
- * @param item
- * The item to deallocate.
- *
- * @see f_string_dynamic_resize()
- */
-#ifndef _di_controller_rule_item_delete_simple_
- extern void controller_rule_item_delete_simple(controller_rule_item_t *item) F_attribute_visibility_internal_d;
-#endif // _di_controller_rule_item_delete_simple_
-
-/**
- * Fully deallocate all memory for the given rule items without caring about return status.
- *
- * @param items
- * The rule_items to deallocate.
- *
- * @see controller_rule_item_delete_simple()
- * @see f_memory_delete()
- */
-#ifndef _di_controller_rule_items_delete_simple_
- extern void controller_rule_items_delete_simple(controller_rule_items_t *items) F_attribute_visibility_internal_d;
-#endif // _di_controller_rule_items_delete_simple_
-
-/**
- * Fully deallocate all memory for the given rule item without caring about return status.
- *
- * @param on
- * The on to deallocate.
- *
- * @see f_string_dynamic_resize()
- */
-#ifndef _di_controller_rule_on_delete_simple_
- extern void controller_rule_on_delete_simple(controller_rule_on_t *on) F_attribute_visibility_internal_d;
-#endif // _di_controller_rule_on_delete_simple_
-
-/**
- * Fully deallocate all memory for the given rule items without caring about return status.
- *
- * @param ons
- * The rule_ons to deallocate.
- *
- * @see controller_rule_on_delete_simple()
- * @see f_memory_delete()
- */
-#ifndef _di_controller_rule_ons_delete_simple_
- extern void controller_rule_ons_delete_simple(controller_rule_ons_t *ons) F_attribute_visibility_internal_d;
-#endif // _di_controller_rule_ons_delete_simple_
-
-/**
- * Increase the size of the rule array, but only if necessary.
- *
- * If the given length is too large for the buffer, then attempt to set max buffer size (F_array_length_t_size_d).
- * If already set to the maximum buffer size, then the resize will fail.
- *
- * @param ons
- * The on array to resize.
- *
- * @return
- * F_none on success.
- * F_data_not on success, but there is no reason to increase size (used + controller_common_allocation_small_d <= size).
- *
- * F_array_too_large (with error bit) if the new array length is too large.
- * F_memory_not (with error bit) on out of memory.
- * F_parameter (with error bit) if a parameter is invalid.
- *
- * @see controller_rule_ons_resize()
- */
-#ifndef _di_controller_rule_ons_increase_
- extern f_status_t controller_rule_ons_increase(controller_rule_ons_t *ons) F_attribute_visibility_internal_d;
-#endif // _di_controller_rule_increase_
-
-/**
- * Resize the rule array.
- *
- * @param length
- * The new size to use.
- * @param ons
- * The on array to resize.
- *
- * @return
- * F_none on success.
- *
- * F_memory_not (with error bit) on out of memory.
- * F_parameter (with error bit) if a parameter is invalid.
- *
- * @see f_memory_resize()
- */
-#ifndef _di_controller_rule_ons_resize_
- extern f_status_t controller_rule_ons_resize(const f_array_length_t length, controller_rule_ons_t *ons) F_attribute_visibility_internal_d;
-#endif // _di_controller_rule_ons_resize_
-
-/**
- * Fully deallocate all memory for the given rules without caring about return status.
- *
- * @param rules
- * The rules to deallocate.
- *
- * @see controller_rules_resize()
- */
-#ifndef _di_controller_rules_delete_simple_
- extern void controller_rules_delete_simple(controller_rules_t *rules) F_attribute_visibility_internal_d;
-#endif // _di_controller_rules_delete_simple_
-
-/**
- * Increase the size of the rule array, but only if necessary.
- *
- * If the given length is too large for the buffer, then attempt to set max buffer size (F_array_length_t_size_d).
- * If already set to the maximum buffer size, then the resize will fail.
- *
- * @param rules
- * The rule array to resize.
- *
- * @return
- * F_none on success.
- * F_data_not on success, but there is no reason to increase size (used + controller_common_allocation_small_d <= size).
- *
- * F_array_too_large (with error bit) if the new array length is too large.
- * F_memory_not (with error bit) on out of memory.
- * F_parameter (with error bit) if a parameter is invalid.
- *
- * @see controller_rules_resize()
- */
-#ifndef _di_controller_rules_increase_
- extern f_status_t controller_rules_increase(controller_rules_t *rules) F_attribute_visibility_internal_d;
-#endif // _di_controller_rule_increase_
-
-/**
- * Resize the rule array.
- *
- * @param length
- * The new size to use.
- * @param rules
- * The rule array to resize.
- *
- * @return
- * F_none on success.
- *
- * F_memory_not (with error bit) on out of memory.
- * F_parameter (with error bit) if a parameter is invalid.
- *
- * @see f_memory_resize()
- */
-#ifndef _di_controller_rules_resize_
- extern f_status_t controller_rules_resize(const f_array_length_t length, controller_rules_t *rules) F_attribute_visibility_internal_d;
-#endif // _di_controller_rules_resize_
-
-/**
- * Fully deallocate all memory for the given setting without caring about return status.
- *
- * @param setting
- * The setting to deallocate.
- *
- * @see controller_entry_delete_simple()
- * @see controller_rules_delete_simple()
- * @see f_string_dynamic_resize()
- */
-#ifndef _di_controller_setting_delete_simple_
- extern void controller_setting_delete_simple(controller_setting_t *setting) F_attribute_visibility_internal_d;
-#endif // _di_controller_setting_delete_simple_
-
-/**
- * Fully deallocate all memory for the given setting without caring about return status.
- *
- * @param thread
- * The thread to deallocate.
- *
- * @see controller_asynchronouss_resize()
- * @see f_thread_mutex_unlock()
- */
-#ifndef _di_controller_thread_delete_simple_
- extern void controller_thread_delete_simple(controller_thread_t * const thread) F_attribute_visibility_internal_d;
-#endif // _di_controller_thread_delete_simple_
-
#ifdef __cplusplus
} // extern "C"
#endif
#endif // _di_controller_string_dynamic_partial_append_terminated_
#ifndef _di_controller_file_load_
- f_status_t controller_file_load(const bool required, const f_string_t path_prefix, const f_string_static_t path_name, const f_string_t path_suffix, const f_array_length_t path_prefix_length, const f_array_length_t path_suffix_length, controller_global_t global, controller_cache_t *cache) {
+ f_status_t controller_file_load(const controller_global_t global, const bool required, const f_string_t path_prefix, const f_string_static_t path_name, const f_string_t path_suffix, const f_array_length_t path_prefix_length, const f_array_length_t path_suffix_length, controller_cache_t * const cache) {
f_status_t status = F_none;
f_file_t file = f_file_t_initialize;
#endif // _di_controller_file_pid_read_
#ifndef _di_controller_get_id_user_
- f_status_t controller_get_id_user(const f_string_static_t buffer, const f_string_range_t range, controller_cache_t *cache, uid_t *id) {
+ f_status_t controller_get_id_user(const f_string_static_t buffer, const f_string_range_t range, controller_cache_t * const cache, uid_t *id) {
f_number_unsigned_t number = 0;
cache->action.generic.used = 0;
status = f_string_dynamic_partial_append_nulless(buffer, range, &cache->action.generic);
+ if (F_status_is_error(status)) return status;
- if (F_status_is_error(status)) {
- return F_status_set_error(status);
- }
+ status = f_string_dynamic_terminate(&cache->action.generic);
+ if (F_status_is_error(status)) return status;
status = f_account_id_user_by_name(cache->action.generic.string, id);
+ if (F_status_is_error(status)) return status;
- if (F_status_is_error(status)) {
- return F_status_set_error(status);
- }
- else if (status == F_exist_not) {
+ if (status == F_exist_not) {
return F_status_set_error(F_exist_not);
}
}
*id = (uid_t) number;
+
return status;
}
#endif // _di_controller_get_id_user_
#ifndef _di_controller_get_id_group_
- f_status_t controller_get_id_group(const f_string_static_t buffer, const f_string_range_t range, controller_cache_t *cache, gid_t *id) {
+ f_status_t controller_get_id_group(const f_string_static_t buffer, const f_string_range_t range, controller_cache_t * const cache, gid_t *id) {
f_number_unsigned_t number = 0;
cache->action.generic.used = 0;
status = f_string_dynamic_partial_append_nulless(buffer, range, &cache->action.generic);
+ if (F_status_is_error(status)) return status;
- if (F_status_is_error(status)) {
- return F_status_set_error(status);
- }
+ status = f_string_dynamic_terminate(&cache->action.generic);
+ if (F_status_is_error(status)) return status;
status = f_account_id_group_by_name(cache->action.generic.string, id);
+ if (F_status_is_error(status)) return status;
- if (F_status_is_error(status)) {
- return F_status_set_error(status);
- }
- else if (status == F_exist_not) {
+ if (status == F_exist_not) {
return F_status_set_error(F_exist_not);
}
}
*id = (gid_t) number;
+
return status;
}
#endif // _di_controller_get_id_group_
#ifndef _di_controller_perform_ready_
- f_status_t controller_perform_ready(const bool is_entry, controller_global_t global, controller_cache_t *cache) {
+ f_status_t controller_perform_ready(const controller_global_t global, const bool is_entry, controller_cache_t * const cache) {
- // Only create pid file when not in validate mode.
- if (!is_entry || global.setting->entry.pid == controller_entry_pid_disable_e || global.main->parameters[controller_parameter_validate_e].result != f_console_result_none_e || !global.setting->path_pid.used) {
+ if (!is_entry) {
return F_none;
}
- f_status_t status = controller_file_pid_create(global.main->pid, global.setting->path_pid);
+ f_status_t status = F_none;
- // Report pid file error but because this could be an "init" program, consider the pid file as optional and continue on.
- if (F_status_is_error(status)) {
+ if (global.setting->entry.pid != controller_entry_pid_disable_e && !global.setting->path_pid.used) {
+ if (global.main->parameters[controller_parameter_validate_e].result == f_console_result_additional_e) {
+ status = controller_file_pid_create(global.main->pid, global.setting->path_pid);
+ }
- // Always return immediately on memory errors.
- if (F_status_set_fine(status) == F_memory_not) {
- if (global.main->error.verbosity != f_console_verbosity_quiet_e) {
- controller_lock_print(global.main->error.to, global.thread);
+ // Report pid file error but because this could be an "init" program, consider the pid file as optional and continue on.
+ if (F_status_is_error(status)) {
+
+ // Always return immediately on memory errors.
+ if (F_status_set_fine(status) == F_memory_not) {
+ if (global.main->error.verbosity != f_console_verbosity_quiet_e) {
+ controller_lock_print(global.main->error.to, global.thread);
- controller_print_error_file(global.main->error, F_status_set_fine(status), "controller_file_pid_create", F_true, global.setting->path_pid.string, "create", fll_error_file_type_file_e, 0);
+ controller_print_error_file(global.main->error, F_status_set_fine(status), "controller_file_pid_create", F_true, global.setting->path_pid.string, "create", fll_error_file_type_file_e, 0);
- flockfile(global.main->error.to.stream);
+ flockfile(global.main->error.to.stream);
- controller_entry_print_error_cache(is_entry, global.main->error, cache->action);
+ controller_entry_print_error_cache(is_entry, global.main->error, cache->action);
- controller_unlock_print_flush(global.main->error.to, global.thread);
+ controller_unlock_print_flush(global.main->error.to, global.thread);
+ }
+
+ return status;
}
- return status;
- }
+ if (global.main->warning.verbosity == f_console_verbosity_debug_e) {
+ controller_lock_print(global.main->warning.to, global.thread);
- if (global.main->warning.verbosity == f_console_verbosity_debug_e) {
- controller_lock_print(global.main->warning.to, global.thread);
+ if (F_status_set_fine(status) == F_read_only) {
+ fl_print_format("%c%[%SThe pid file '%]", global.main->warning.to.stream, f_string_eol_s[0], global.main->warning.context, global.main->warning.prefix, global.main->warning.context);
+ fl_print_format("%[%Q%]", global.main->warning.to.stream, global.main->warning.notable, global.setting->path_pid, global.main->warning.notable);
+ fl_print_format("%[' could not be written because the destination is read only.%]%c", global.main->warning.to.stream, global.main->warning.context, global.main->warning.context, f_string_eol_s[0]);
+ }
+ else {
+ controller_print_error_file(global.main->warning, F_status_set_fine(status), "controller_file_pid_create", F_true, global.setting->path_pid.string, "create", fll_error_file_type_file_e, 0);
+ }
- if (F_status_set_fine(status) == F_read_only) {
- fl_print_format("%c%[%SThe pid file '%]", global.main->warning.to.stream, f_string_eol_s[0], global.main->warning.context, global.main->warning.prefix ? global.main->warning.prefix : f_string_empty_s, global.main->warning.context);
- fl_print_format("%[%Q%]", global.main->warning.to.stream, global.main->warning.notable, global.setting->path_pid, global.main->warning.notable);
- fl_print_format("%[' could not be written because the destination is read only.%]%c", global.main->warning.to.stream, global.main->warning.context, global.main->warning.context, f_string_eol_s[0]);
+ controller_entry_print_error_cache(is_entry, global.main->warning, cache->action);
+
+ controller_unlock_print_flush(global.main->warning.to, global.thread);
}
- else {
- controller_print_error_file(global.main->warning, F_status_set_fine(status), "controller_file_pid_create", F_true, global.setting->path_pid.string, "create", fll_error_file_type_file_e, 0);
+
+ status = F_none;
+ }
+ else {
+ global.setting->pid_created = F_true;
+
+ if (global.main->output.verbosity == f_console_verbosity_debug_e) {
+ controller_lock_print(global.main->output.to, global.thread);
+
+ fl_print_format("%cPID file '", global.main->output.to.stream, f_string_eol_s[0]);
+ fl_print_format("%[%Q%]", global.main->output.to.stream, global.main->context.set.notable, global.setting->path_pid, global.main->context.set.notable);
+
+ if (global.main->parameters[controller_parameter_validate_e].result == f_console_result_none_e) {
+ fl_print_format("' created.%c", global.main->output.to.stream, f_string_eol_s[0]);
+ }
+ else {
+ fl_print_format("'.%c", global.main->output.to.stream, f_string_eol_s[0]);
+ }
+
+ controller_unlock_print_flush(global.main->output.to, global.thread);
}
+ }
+ }
+
+ if (global.setting->path_control.used) {
+ if (global.setting->control_readonly) {
+ if (f_file_exists(global.setting->path_control.string) != F_true) {
+ if (global.main->output.verbosity == f_console_verbosity_debug_e) {
+ controller_lock_print(global.main->output.to, global.thread);
- controller_entry_print_error_cache(is_entry, global.main->warning, cache->action);
+ fl_print_format("%c%[%SControl socket '%]", global.main->warning.to.stream, f_string_eol_s[0], global.main->warning.context, global.main->warning.prefix, global.main->warning.context);
+ fl_print_format("%[%Q%]", global.main->output.to.stream, global.main->context.set.notable, global.setting->path_control, global.main->context.set.notable);
+ fl_print_format("' .%c", global.main->output.to.stream, f_string_eol_s[0]);
+ fl_print_format("%[' cannot be found while read only mode is enabled and so the Control socket is unavailable.%]%c", global.main->output.to.stream, global.main->warning.context, global.main->warning.context, f_string_eol_s[0]);
- controller_unlock_print_flush(global.main->warning.to, global.thread);
+ controller_unlock_print_flush(global.main->output.to, global.thread);
+ }
+
+ return status;
+ }
}
+ else {
+ status = f_socket_create(&global.setting->control_socket);
- status = F_none;
- }
- else {
- global.setting->pid_created = F_true;
+ if (F_status_is_error(status)) {
+ if (F_status_set_fine(status) == F_memory_not) {
+ controller_print_error(global.main->error, F_status_set_fine(status), "f_socket_create", F_true, global.thread);
+
+ return status;
+ }
+
+ if (global.main->output.verbosity == f_console_verbosity_debug_e) {
+ controller_lock_print(global.main->output.to, global.thread);
+
+ fl_print_format("%c%[%SControl socket '%]", global.main->warning.to.stream, f_string_eol_s[0], global.main->warning.context, global.main->warning.prefix, global.main->warning.context);
+ fl_print_format("%[%Q%]", global.main->output.to.stream, global.main->context.set.notable, global.setting->path_control, global.main->context.set.notable);
+ fl_print_format("%[' could not be created, code %]", global.main->output.to.stream, global.main->warning.context, global.main->warning.context);
+ fl_print_format("%[%ui%]", global.main->output.to.stream, global.main->context.set.notable, F_status_set_fine(status), global.main->context.set.notable);
+ fl_print_format("%[.%]%c", global.main->output.to.stream, global.main->warning.context, global.main->warning.context, f_string_eol_s[0]);
+
+ controller_unlock_print_flush(global.main->output.to, global.thread);
+ }
+ }
+ else {
+ status = f_file_remove(global.setting->path_control.string);
+
+ if (F_status_set_fine(status) == F_memory_not) {
+ controller_print_error(global.main->error, F_status_set_fine(status), "f_file_remove", F_true, global.thread);
+
+ return status;
+ }
+
+ global.setting->control_socket.name = global.setting->path_control.string;
+
+ status = f_socket_bind_file(global.setting->control_socket);
+
+ if (F_status_is_error(status)) {
+ f_socket_disconnect(&global.setting->control_socket, f_socket_close_fast_e);
+
+ if (F_status_set_fine(status) == F_memory_not) {
+ controller_print_error(global.main->error, F_status_set_fine(status), "f_socket_bind_file", F_true, global.thread);
+
+ return status;
+ }
+
+ if (global.main->output.verbosity == f_console_verbosity_debug_e) {
+ controller_lock_print(global.main->output.to, global.thread);
+
+ fl_print_format("%c%[%SControl socket '%]", global.main->warning.to.stream, f_string_eol_s[0], global.main->warning.context, global.main->warning.prefix, global.main->warning.context);
+ fl_print_format("%[%Q%]", global.main->output.to.stream, global.main->context.set.notable, global.setting->path_control, global.main->context.set.notable);
+ fl_print_format("%[' could not be bound, code %]", global.main->output.to.stream, global.main->warning.context, global.main->warning.context);
+ fl_print_format("%[%ui%]", global.main->output.to.stream, global.main->context.set.notable, F_status_set_fine(status), global.main->context.set.notable);
+ fl_print_format("%[.%]%c", global.main->output.to.stream, global.main->warning.context, global.main->warning.context, f_string_eol_s[0]);
+
+ controller_unlock_print_flush(global.main->output.to, global.thread);
+ }
+ }
+ else {
+ status = f_file_role_change(global.setting->path_control.string, global.setting->control_user, global.setting->control_group, F_true);
+
+ if (F_status_is_error(status)) {
+ f_socket_disconnect(&global.setting->control_socket, f_socket_close_fast_e);
+
+ if (F_status_set_fine(status) == F_memory_not) {
+ controller_print_error(global.main->error, F_status_set_fine(status), "f_file_role_change", F_true, global.thread);
+
+ return status;
+ }
+
+ if (global.main->output.verbosity == f_console_verbosity_debug_e) {
+ controller_lock_print(global.main->output.to, global.thread);
+
+ fl_print_format("%c%[%SControl socket '%]", global.main->warning.to.stream, f_string_eol_s[0], global.main->warning.context, global.main->warning.prefix, global.main->warning.context);
+ fl_print_format("%[%Q%]", global.main->output.to.stream, global.main->context.set.notable, global.setting->path_control, global.main->context.set.notable);
+ fl_print_format("%[' failed to set file roles, code %]", global.main->output.to.stream, global.main->warning.context, global.main->warning.context);
+ fl_print_format("%[%ui%]", global.main->output.to.stream, global.main->context.set.notable, F_status_set_fine(status), global.main->context.set.notable);
+ fl_print_format("%[.%]%c", global.main->output.to.stream, global.main->warning.context, global.main->warning.context, f_string_eol_s[0]);
+
+ controller_unlock_print_flush(global.main->output.to, global.thread);
+ }
+ }
+ else {
+ status = f_file_mode_set(global.setting->path_control.string, global.setting->control_mode);
+
+ if (F_status_is_error(status)) {
+ f_socket_disconnect(&global.setting->control_socket, f_socket_close_fast_e);
+
+ if (F_status_set_fine(status) == F_memory_not) {
+ controller_print_error(global.main->error, F_status_set_fine(status), "f_file_role_change", F_true, global.thread);
+
+ return status;
+ }
+
+ if (global.main->output.verbosity == f_console_verbosity_debug_e) {
+ controller_lock_print(global.main->output.to, global.thread);
+
+ fl_print_format("%c%[%SControl socket '%]", global.main->warning.to.stream, f_string_eol_s[0], global.main->warning.context, global.main->warning.prefix, global.main->warning.context);
+ fl_print_format("%[%Q%]", global.main->output.to.stream, global.main->context.set.notable, global.setting->path_control, global.main->context.set.notable);
+ fl_print_format("%[' failed to set file mode, code %]", global.main->output.to.stream, global.main->warning.context, global.main->warning.context);
+ fl_print_format("%[%ui%]", global.main->output.to.stream, global.main->context.set.notable, F_status_set_fine(status), global.main->context.set.notable);
+ fl_print_format("%[.%]%c", global.main->output.to.stream, global.main->warning.context, global.main->warning.context, f_string_eol_s[0]);
+
+ controller_unlock_print_flush(global.main->output.to, global.thread);
+ }
+ }
+ else {
+ if (global.main->output.verbosity == f_console_verbosity_debug_e) {
+ controller_lock_print(global.main->output.to, global.thread);
+
+ fl_print_format("%cControl socket '", global.main->output.to.stream, f_string_eol_s[0]);
+ fl_print_format("%[%Q%]", global.main->output.to.stream, global.main->context.set.notable, global.setting->path_control, global.main->context.set.notable);
+
+ if (global.main->parameters[controller_parameter_validate_e].result == f_console_result_none_e) {
+ fl_print_format("' created.%c", global.main->output.to.stream, f_string_eol_s[0]);
+ }
+ else {
+ fl_print_format("'.%c", global.main->output.to.stream, f_string_eol_s[0]);
+ }
+
+ controller_unlock_print_flush(global.main->output.to, global.thread);
+ }
+
+ // @todo start the control thread.
+ }
+ }
+ }
+ }
+
+ // Don't fail if unable to create socket file.
+ status = F_none;
+ }
}
return status;
#endif // _di_controller_range_after_number_sign_
/**
- * Rip a string fromt he source and then add a NULL after the end of the string.
+ * Rip a string from the source and then add a NULL after the end of the string.
*
* @param source
* The string to copy from.
/**
* Load a file from the controller settings directory.
*
+ * @param global
+ * The global data.
* @param required
* If TRUE, the file is required to exist and will throw an error if not found.
* If FALSE, the file is not required to exist and will return without error if not found.
* The length of the prefix path.
* @param path_suffix_length
* The length of the suffix path.
- * @param global
- * The global data.
* @param cache
* The following within the cache is updated:
* - name_file: The partial path of the file is inserted.
* @see f_string_dynamic_terminate_after()
*/
#ifndef _di_controller_file_load_
- extern f_status_t controller_file_load(const bool required, const f_string_t path_prefix, const f_string_static_t path_name, const f_string_t path_suffix, const f_array_length_t path_prefix_length, const f_array_length_t path_suffix_length, controller_global_t global, controller_cache_t *cache) F_attribute_visibility_internal_d;
+ extern f_status_t controller_file_load(const controller_global_t global, const bool required, const f_string_t path_prefix, const f_string_static_t path_name, const f_string_t path_suffix, const f_array_length_t path_prefix_length, const f_array_length_t path_suffix_length, controller_cache_t * const cache) F_attribute_visibility_internal_d;
#endif // _di_controller_file_load_
/**
* @see fl_conversion_string_to_number_unsigned()
*/
#ifndef _di_controller_get_id_user_
- f_status_t controller_get_id_user(const f_string_static_t buffer, const f_string_range_t range, controller_cache_t *cache, uid_t *id) F_attribute_visibility_internal_d;
+ f_status_t controller_get_id_user(const f_string_static_t buffer, const f_string_range_t range, controller_cache_t * const cache, uid_t *id) F_attribute_visibility_internal_d;
#endif // _di_controller_get_id_user_
/**
* @see fl_conversion_string_to_number_unsigned()
*/
#ifndef _di_controller_get_id_group_
- f_status_t controller_get_id_group(const f_string_static_t buffer, const f_string_range_t range, controller_cache_t *cache, gid_t *id) F_attribute_visibility_internal_d;
+ f_status_t controller_get_id_group(const f_string_static_t buffer, const f_string_range_t range, controller_cache_t * const cache, gid_t *id) F_attribute_visibility_internal_d;
#endif // _di_controller_get_id_group_
/**
*
* This does not do any locking or unlocking for the setting data, be sure to lock appropriately before and after calling this.
*
+ * @param global
+ * The global data.
* @param is_entry
* If TRUE, then this operate as an entry.
* If FALSE, then this operate as an exit.
- * @param global
- * The global data.
* @param cache
* The cache.
*
* @see controller_file_pid_create()
*/
#ifndef _di_controller_perform_ready_
- extern f_status_t controller_perform_ready(const bool is_entry, controller_global_t global, controller_cache_t *cache) F_attribute_visibility_internal_d;
+ extern f_status_t controller_perform_ready(const controller_global_t global, const bool is_entry, controller_cache_t * const cache) F_attribute_visibility_internal_d;
#endif // _di_controller_perform_ready_
/**
#endif // _di_controller_entry_action_type_to_rule_action_type_
#ifndef _di_controller_entry_actions_read_
- f_status_t controller_entry_actions_read(const bool is_entry, const f_string_range_t content_range, controller_global_t global, controller_cache_t *cache, controller_entry_actions_t *actions) {
+ f_status_t controller_entry_actions_read(const controller_global_t global, const bool is_entry, const f_string_range_t content_range, controller_cache_t * const cache, controller_entry_actions_t *actions) {
f_status_t status = F_none;
f_status_t status_action = F_none;
if (action->type == controller_entry_action_type_consider_e || controller_entry_action_type_is_rule(action->type)) {
if (action->parameters.array[0].used) {
- // force the path to be canonical (removing all '../' parts).
+ // Force the path to be canonical (removing all '../' parts).
status = fll_path_canonical(action->parameters.array[0].string, &cache->buffer_path);
if (F_status_is_error(status)) {
+ // @todo instead call: fll_error_file_print().
+ // fll_error_file_print(main->error, F_status_set_fine(status), "fll_path_canonical", F_true, arguments->argv[location], "verify", fll_error_file_type_path_e);
controller_entry_print_error(is_entry, global.main->error, cache->action, F_status_set_fine(status), "fll_path_canonical", F_true, global.thread);
action->status = status;
#endif // _di_controller_entry_actions_read_
#ifndef _di_controller_entry_preprocess_
- f_status_t controller_entry_preprocess(const bool is_entry, controller_global_t global, controller_cache_t *cache) {
+ f_status_t controller_entry_preprocess(const controller_global_t global, const bool is_entry, controller_cache_t * const cache) {
f_status_t status = F_none;
f_status_t status2 = F_none;
// This effectively sets the read for an entry and resets the ready for an exit.
// @todo should there be a ready_exit instead?
// @todo the global.setting->ready in this function may need mutex lock protection.
+ // @todo disconnect the socket file if applicable.
global.setting->ready = controller_setting_ready_no_e;
cache->ats.used = 0;
return status;
}
- // utilize the ats cache as an item execution stack (at_i is for item index, and at_j (at_i + 1) is for action index).
+ // Utilize the ats cache as an item execution stack (at_i is for item index, and at_j (at_i + 1) is for action index).
cache->ats.array[0] = 0;
cache->ats.array[1] = 0;
cache->ats.used = 2;
continue;
}
- // walk though each items and check to see if the item actually exists.
+ // Walk though each items and check to see if the item actually exists.
for (i = 1; i < entry->items.used && controller_thread_is_enabled(is_entry, global.thread); ++i) {
if (fl_string_dynamic_compare(entry->items.array[i].name, actions->array[cache->ats.array[at_j]].parameters.array[0]) == F_equal_to) {
- // check to see if "i" is already in the stack (to prevent recursion) (skipping main).
+ // Check to see if "i" is already in the stack (to prevent recursion) (skipping main).
for (j = 2; j < cache->ats.used; j += 2) {
if (cache->ats.array[j] == i) {
return status2;
}
- // save the value so to avoid string comparison during normal operation.
+ // Save the value so to avoid string comparison during normal operation.
actions->array[cache->ats.array[at_j]].number = i;
- // continue into the requested item.
+ // Continue into the requested item.
at_i = cache->ats.used;
at_j = cache->ats.used + 1;
cache->action.line_action = 0;
cache->action.name_action.used = 0;
- // end of actions found, so drop to previous loop in stack.
+ // End of actions found, so drop to previous loop in stack.
if (cache->ats.array[at_j] == actions->used) {
- // all actions for "main" are processed so there is nothing left to do.
+ // All actions for "main" are processed so there is nothing left to do.
if (at_i == 0) break;
at_i -= 2;
return F_status_set_error(F_interrupt);
}
- // if ready was never found in the entry, then default to always ready.
+ // If ready was never found in the entry, then default to always ready.
if (global.setting->ready == controller_setting_ready_no_e) {
global.setting->ready = controller_setting_ready_yes_e;
+
+ // @todo set socket file if applicable.
}
return status;
#endif // _di_controller_entry_preprocess_
#ifndef _di_controller_entry_process_
- f_status_t controller_entry_process(const bool failsafe, const bool is_entry, controller_global_t *global, controller_cache_t *cache) {
+ f_status_t controller_entry_process(const controller_global_t global, const bool failsafe, const bool is_entry, controller_cache_t * const cache) {
f_status_t status = F_none;
f_status_t status_lock = F_none;
uint8_t options_force = 0;
uint8_t options_process = 0;
- controller_entry_t *entry = is_entry ? &global->setting->entry : &global->setting->exit;
+ controller_entry_t *entry = is_entry ? &global.setting->entry : &global.setting->exit;
controller_entry_action_t *entry_action = 0;
controller_entry_actions_t *entry_actions = 0;
controller_process_t *process = 0;
macro_f_array_lengths_t_increase_by(status, cache->ats, controller_common_allocation_small_d)
if (F_status_is_error(status)) {
- controller_entry_print_error(is_entry, global->main->error, cache->action, F_status_set_fine(status), "macro_f_array_lengths_t_increase_by", F_true, global->thread);
+ controller_entry_print_error(is_entry, global.main->error, cache->action, F_status_set_fine(status), "macro_f_array_lengths_t_increase_by", F_true, global.thread);
return status;
}
// utilize the ats cache as an item execution stack (at_i is for item index, and at_j (at_i + 1) is for action index).
- cache->ats.array[0] = failsafe ? global->setting->failsafe_item_id : 0;
+ cache->ats.array[0] = failsafe ? global.setting->failsafe_item_id : 0;
cache->ats.array[1] = 0;
cache->ats.used = 2;
status = controller_dynamic_append_terminated(entry->items.array[cache->ats.array[0]].name, &cache->action.name_item);
if (F_status_is_error(status)) {
- controller_entry_print_error(is_entry, global->main->error, cache->action, F_status_set_fine(status), "controller_dynamic_append_terminated", F_true, global->thread);
+ controller_entry_print_error(is_entry, global.main->error, cache->action, F_status_set_fine(status), "controller_dynamic_append_terminated", F_true, global.thread);
return status;
}
- if (global->main->parameters[controller_parameter_simulate_e].result == f_console_result_found_e || global->main->error.verbosity == f_console_verbosity_verbose_e || global->main->error.verbosity == f_console_verbosity_debug_e) {
- if (global->main->error.verbosity != f_console_verbosity_quiet_e) {
- controller_lock_print(global->main->output.to, global->thread);
+ if (global.main->parameters[controller_parameter_simulate_e].result == f_console_result_found_e || global.main->error.verbosity == f_console_verbosity_verbose_e || global.main->error.verbosity == f_console_verbosity_debug_e) {
+ if (global.main->error.verbosity != f_console_verbosity_quiet_e) {
+ controller_lock_print(global.main->output.to, global.thread);
- fl_print_format("%cProcessing %s%s item '", global->main->output.to.stream, f_string_eol_s[0], failsafe ? "failsafe " : "", is_entry ? controller_entry_s : controller_exit_s);
- fl_print_format("%[%Q%]'.%c", global->main->output.to.stream, global->main->context.set.notable, cache->action.name_item, global->main->context.set.notable, f_string_eol_s[0]);
+ fl_print_format("%cProcessing %s%s item '", global.main->output.to.stream, f_string_eol_s[0], failsafe ? "failsafe " : "", is_entry ? controller_entry_s : controller_exit_s);
+ fl_print_format("%[%Q%]'.%c", global.main->output.to.stream, global.main->context.set.notable, cache->action.name_item, global.main->context.set.notable, f_string_eol_s[0]);
- controller_unlock_print_flush(global->main->output.to, global->thread);
+ controller_unlock_print_flush(global.main->output.to, global.thread);
}
}
- while (controller_thread_is_enabled(is_entry, global->thread)) {
+ while (controller_thread_is_enabled(is_entry, global.thread)) {
entry_actions = &entry->items.array[cache->ats.array[at_i]].actions;
- for (; cache->ats.array[at_j] < entry_actions->used && controller_thread_is_enabled(is_entry, global->thread); ++cache->ats.array[at_j]) {
+ for (; cache->ats.array[at_j] < entry_actions->used && controller_thread_is_enabled(is_entry, global.thread); ++cache->ats.array[at_j]) {
entry_action = &entry_actions->array[cache->ats.array[at_j]];
status = controller_dynamic_append_terminated(controller_entry_action_type_name(entry_action->type), &cache->action.name_action);
if (F_status_is_error(status)) {
- controller_entry_print_error(is_entry, global->main->error, cache->action, F_status_set_fine(status), "controller_dynamic_append_terminated", F_true, global->thread);
+ controller_entry_print_error(is_entry, global.main->error, cache->action, F_status_set_fine(status), "controller_dynamic_append_terminated", F_true, global.thread);
return status;
}
if (F_status_is_error(entry_action->status)) {
- if (global->main->parameters[controller_parameter_simulate_e].result == f_console_result_found_e) {
- if (global->main->error.verbosity != f_console_verbosity_quiet_e) {
- controller_lock_print(global->main->output.to, global->thread);
+ if (global.main->parameters[controller_parameter_simulate_e].result == f_console_result_found_e) {
+ if (global.main->error.verbosity != f_console_verbosity_quiet_e) {
+ controller_lock_print(global.main->output.to, global.thread);
- fl_print_format("%cThe %s item action '", global->main->output.to.stream, f_string_eol_s[0], is_entry ? controller_entry_s : controller_exit_s);
- fl_print_format("%[%Q%]", global->main->output.to.stream, global->main->context.set.title, cache->action.name_action, global->main->context.set.title);
+ fl_print_format("%cThe %s item action '", global.main->output.to.stream, f_string_eol_s[0], is_entry ? controller_entry_s : controller_exit_s);
+ fl_print_format("%[%Q%]", global.main->output.to.stream, global.main->context.set.title, cache->action.name_action, global.main->context.set.title);
if (entry_action->parameters.used) {
- fl_print_format(" %[", global->main->output.to.stream, global->main->context.set.notable);
+ fl_print_format(" %[", global.main->output.to.stream, global.main->context.set.notable);
- controller_entry_action_parameters_print(global->main->output.to.stream, *entry_action);
+ controller_entry_action_parameters_print(global.main->output.to.stream, *entry_action);
- fl_print_format("%]", global->main->output.to.stream, global->main->context.set.notable);
+ fl_print_format("%]", global.main->output.to.stream, global.main->context.set.notable);
}
- fl_print_format("' is %[%s%] and is in a ", global->main->output.to.stream, global->main->context.set.notable, entry_action->code & controller_entry_rule_code_require_d ? "required" : "optional", global->main->context.set.notable);
+ fl_print_format("' is %[%s%] and is in a ", global.main->output.to.stream, global.main->context.set.notable, entry_action->code & controller_entry_rule_code_require_d ? "required" : "optional", global.main->context.set.notable);
- fl_print_format("%[failed%] state, skipping.%c", global->main->output.to.stream, global->main->context.set.notable, global->main->context.set.notable, global->main->context.set.notable, f_string_eol_s[0]);
+ fl_print_format("%[failed%] state, skipping.%c", global.main->output.to.stream, global.main->context.set.notable, global.main->context.set.notable, global.main->context.set.notable, f_string_eol_s[0]);
- controller_unlock_print_flush(global->main->output.to, global->thread);
+ controller_unlock_print_flush(global.main->output.to, global.thread);
}
}
else {
- if ((entry_action->code & controller_entry_rule_code_require_d) && global->main->error.verbosity != f_console_verbosity_quiet_e || !(entry_action->code & controller_entry_rule_code_require_d) && (global->main->warning.verbosity == f_console_verbosity_verbose_e || global->main->warning.verbosity == f_console_verbosity_debug_e)) {
+ if ((entry_action->code & controller_entry_rule_code_require_d) && global.main->error.verbosity != f_console_verbosity_quiet_e || !(entry_action->code & controller_entry_rule_code_require_d) && (global.main->warning.verbosity == f_console_verbosity_verbose_e || global.main->warning.verbosity == f_console_verbosity_debug_e)) {
fl_print_t *output = 0;
if (entry_action->code & controller_entry_rule_code_require_d) {
- output = &global->main->error;
+ output = &global.main->error;
}
else {
- output = &global->main->warning;
+ output = &global.main->warning;
}
- controller_lock_print(output->to, global->thread);
+ controller_lock_print(output->to, global.thread);
fl_print_format("%c%[%SThe %s item action '%]", output->to.stream, f_string_eol_s[0], output->context, output->prefix ? output->prefix : f_string_empty_s, is_entry ? controller_entry_s : controller_exit_s, output->context);
fl_print_format("%[%Q%]", output->to.stream, output->notable, cache->action.name_action, output->notable);
if (entry_action->parameters.used) {
- fl_print_format(" %[", output->to.stream, global->main->context.set.notable);
+ fl_print_format(" %[", output->to.stream, global.main->context.set.notable);
controller_entry_action_parameters_print(output->to.stream, *entry_action);
- fl_print_format("%]", output->to.stream, global->main->context.set.notable);
+ fl_print_format("%]", output->to.stream, global.main->context.set.notable);
}
if (entry_action->code & controller_entry_rule_code_require_d) {
controller_entry_print_error_cache(is_entry, *output, cache->action);
- controller_unlock_print_flush(output->to, global->thread);
+ controller_unlock_print_flush(output->to, global.thread);
}
if (controller_entry_action_type_is_rule(entry_action->type) && entry_action->code & controller_entry_rule_code_require_d) {
}
if (entry_action->type == controller_entry_action_type_ready_e) {
- if ((entry_action->code & controller_entry_rule_code_wait_d) || global->setting->ready == controller_setting_ready_wait_e) {
- if (global->main->parameters[controller_parameter_simulate_e].result == f_console_result_found_e || global->main->error.verbosity == f_console_verbosity_verbose_e || global->main->error.verbosity == f_console_verbosity_debug_e || entry->show == controller_entry_show_init_e) {
- if (global->main->output.verbosity != f_console_verbosity_quiet_e) {
- controller_lock_print(global->main->output.to, global->thread);
+ if ((entry_action->code & controller_entry_rule_code_wait_d) || global.setting->ready == controller_setting_ready_wait_e) {
+ if (global.main->parameters[controller_parameter_simulate_e].result == f_console_result_found_e || global.main->error.verbosity == f_console_verbosity_verbose_e || global.main->error.verbosity == f_console_verbosity_debug_e || entry->show == controller_entry_show_init_e) {
+ if (global.main->output.verbosity != f_console_verbosity_quiet_e) {
+ controller_lock_print(global.main->output.to, global.thread);
- fl_print_format("%cWaiting before processing %s item action '", global->main->output.to.stream, f_string_eol_s[0], is_entry ? controller_entry_s : controller_exit_s);
- fl_print_format("%[%s%]", global->main->output.to.stream, global->main->context.set.title, controller_ready_s, global->main->context.set.title);
- fl_print_format("'.%c", global->main->output.to.stream, f_string_eol_s[0]);
+ fl_print_format("%cWaiting before processing %s item action '", global.main->output.to.stream, f_string_eol_s[0], is_entry ? controller_entry_s : controller_exit_s);
+ fl_print_format("%[%s%]", global.main->output.to.stream, global.main->context.set.title, controller_ready_s, global.main->context.set.title);
+ fl_print_format("'.%c", global.main->output.to.stream, f_string_eol_s[0]);
- controller_unlock_print_flush(global->main->output.to, global->thread);
+ controller_unlock_print_flush(global.main->output.to, global.thread);
}
}
- if (global->main->parameters[controller_parameter_validate_e].result == f_console_result_none_e) {
- status = controller_rule_wait_all(is_entry, *global, F_false, process);
+ if (global.main->parameters[controller_parameter_validate_e].result == f_console_result_none_e) {
+ status = controller_rule_wait_all(global, is_entry, F_false, process);
if (F_status_is_error(status)) return status;
}
}
- if (global->setting->ready == controller_setting_ready_yes_e) {
- if (global->main->parameters[controller_parameter_simulate_e].result == f_console_result_found_e || global->main->error.verbosity == f_console_verbosity_verbose_e || global->main->error.verbosity == f_console_verbosity_debug_e) {
- if (global->main->output.verbosity != f_console_verbosity_quiet_e) {
- controller_lock_print(global->main->output.to, global->thread);
+ if (global.setting->ready == controller_setting_ready_yes_e) {
+ if (global.main->parameters[controller_parameter_simulate_e].result == f_console_result_found_e || global.main->error.verbosity == f_console_verbosity_verbose_e || global.main->error.verbosity == f_console_verbosity_debug_e) {
+ if (global.main->output.verbosity != f_console_verbosity_quiet_e) {
+ controller_lock_print(global.main->output.to, global.thread);
- fl_print_format("%cIgnoring %s item action '", global->main->output.to.stream, f_string_eol_s[0], is_entry ? controller_entry_s : controller_exit_s);
- fl_print_format("%[%s%]", global->main->output.to.stream, global->main->context.set.title, controller_ready_s, global->main->context.set.title);
- fl_print_format("', state already is ready.%c", global->main->output.to.stream, f_string_eol_s[0]);
+ fl_print_format("%cIgnoring %s item action '", global.main->output.to.stream, f_string_eol_s[0], is_entry ? controller_entry_s : controller_exit_s);
+ fl_print_format("%[%s%]", global.main->output.to.stream, global.main->context.set.title, controller_ready_s, global.main->context.set.title);
+ fl_print_format("', state already is ready.%c", global.main->output.to.stream, f_string_eol_s[0]);
- controller_unlock_print_flush(global->main->output.to, global->thread);
+ controller_unlock_print_flush(global.main->output.to, global.thread);
}
}
}
else {
- if (!failsafe && (global->main->error.verbosity == f_console_verbosity_verbose_e || entry->show == controller_entry_show_init_e) && global->main->parameters[controller_parameter_simulate_e].result == f_console_result_none_e) {
- fl_print_format("%cState is now '%[%s%]'.%c", global->main->output.to.stream, f_string_eol_s[0], global->main->context.set.notable, controller_ready_s, global->main->context.set.notable, f_string_eol_s[0]);
+ if (!failsafe && (global.main->error.verbosity == f_console_verbosity_verbose_e || entry->show == controller_entry_show_init_e) && global.main->parameters[controller_parameter_simulate_e].result == f_console_result_none_e) {
+ fl_print_format("%cState is now '%[%s%]'.%c", global.main->output.to.stream, f_string_eol_s[0], global.main->context.set.notable, controller_ready_s, global.main->context.set.notable, f_string_eol_s[0]);
}
- status = controller_perform_ready(is_entry, *global, cache);
+ status = controller_perform_ready(global, is_entry, cache);
if (F_status_is_error(status)) return status;
}
}
else if (entry_action->type == controller_entry_action_type_item_e) {
- if (entry_action->number == 0 || entry_action->number >= entry->items.used || failsafe && entry_action->number == global->setting->failsafe_item_id) {
+ if (entry_action->number == 0 || entry_action->number >= entry->items.used || failsafe && entry_action->number == global.setting->failsafe_item_id) {
// This should not happen if the pre-process is working as intended, but in case it doesn't, return a critical error to prevent infinite recursion and similar errors.
- if (global->main->error.verbosity != f_console_verbosity_quiet_e) {
- controller_lock_print(global->main->error.to, global->thread);
+ if (global.main->error.verbosity != f_console_verbosity_quiet_e) {
+ controller_lock_print(global.main->error.to, global.thread);
- fl_print_format("%c%[Invalid %s item index '%]", global->main->error.to.stream, f_string_eol_s[0], global->main->error.context, is_entry ? controller_entry_s : controller_exit_s, global->main->error.context);
- fl_print_format("%[%un%]", global->main->error.to.stream, global->main->error.notable, entry_action->number, global->main->error.notable);
- fl_print_format("%[' detected.%]%c", global->main->error.to.stream, global->main->error.context, global->main->error.context, f_string_eol_s[0]);
+ fl_print_format("%c%[Invalid %s item index '%]", global.main->error.to.stream, f_string_eol_s[0], global.main->error.context, is_entry ? controller_entry_s : controller_exit_s, global.main->error.context);
+ fl_print_format("%[%un%]", global.main->error.to.stream, global.main->error.notable, entry_action->number, global.main->error.notable);
+ fl_print_format("%[' detected.%]%c", global.main->error.to.stream, global.main->error.context, global.main->error.context, f_string_eol_s[0]);
- controller_entry_print_error_cache(is_entry, global->main->error, cache->action);
+ controller_entry_print_error_cache(is_entry, global.main->error, cache->action);
- controller_unlock_print_flush(global->main->error.to, global->thread);
+ controller_unlock_print_flush(global.main->error.to, global.thread);
}
return F_status_is_error(F_critical);
macro_f_array_lengths_t_increase_by(status, cache->ats, controller_common_allocation_small_d)
if (F_status_is_error(status)) {
- controller_entry_print_error(is_entry, global->main->error, cache->action, F_status_set_fine(status), "macro_f_array_lengths_t_increase_by", F_true, global->thread);
+ controller_entry_print_error(is_entry, global.main->error, cache->action, F_status_set_fine(status), "macro_f_array_lengths_t_increase_by", F_true, global.thread);
return status;
}
status = controller_dynamic_append_terminated(entry->items.array[cache->ats.array[at_i]].name, &cache->action.name_item);
if (F_status_is_error(status)) {
- controller_entry_print_error(is_entry, global->main->error, cache->action, F_status_set_fine(status), "controller_dynamic_append_terminated", F_true, global->thread);
+ controller_entry_print_error(is_entry, global.main->error, cache->action, F_status_set_fine(status), "controller_dynamic_append_terminated", F_true, global.thread);
return status;
}
- if (global->main->parameters[controller_parameter_simulate_e].result == f_console_result_found_e || global->main->error.verbosity == f_console_verbosity_verbose_e || global->main->error.verbosity == f_console_verbosity_debug_e) {
- if (global->main->output.verbosity != f_console_verbosity_quiet_e) {
- controller_lock_print(global->main->output.to, global->thread);
+ if (global.main->parameters[controller_parameter_simulate_e].result == f_console_result_found_e || global.main->error.verbosity == f_console_verbosity_verbose_e || global.main->error.verbosity == f_console_verbosity_debug_e) {
+ if (global.main->output.verbosity != f_console_verbosity_quiet_e) {
+ controller_lock_print(global.main->output.to, global.thread);
- fl_print_format("%cProcessing %s item '", global->main->output.to.stream, f_string_eol_s[0], is_entry ? controller_entry_s : controller_exit_s);
- fl_print_format("%[%Q%]", global->main->output.to.stream, global->main->context.set.title, cache->action.name_item, global->main->context.set.title);
- fl_print_format("'.%c", global->main->output.to.stream, f_string_eol_s[0]);
+ fl_print_format("%cProcessing %s item '", global.main->output.to.stream, f_string_eol_s[0], is_entry ? controller_entry_s : controller_exit_s);
+ fl_print_format("%[%Q%]", global.main->output.to.stream, global.main->context.set.title, cache->action.name_item, global.main->context.set.title);
+ fl_print_format("'.%c", global.main->output.to.stream, f_string_eol_s[0]);
- controller_unlock_print_flush(global->main->output.to, global->thread);
+ controller_unlock_print_flush(global.main->output.to, global.thread);
}
}
break;
}
else if (entry_action->type == controller_entry_action_type_consider_e || controller_entry_action_type_is_rule(entry_action->type)) {
- status_lock = controller_lock_write(is_entry, global->thread, &global->thread->lock.rule);
+ status_lock = controller_lock_write(is_entry, global.thread, &global.thread->lock.rule);
if (F_status_is_error(status_lock)) {
- controller_lock_print_error_critical(global->main->error, F_status_set_fine(status_lock), F_false, global->thread);
+ controller_lock_print_error_critical(global.main->error, F_status_set_fine(status_lock), F_false, global.thread);
break;
}
- status = controller_rules_increase(&global->setting->rules);
+ status = controller_rules_increase(&global.setting->rules);
- f_thread_unlock(&global->thread->lock.rule);
+ f_thread_unlock(&global.thread->lock.rule);
if (F_status_is_error(status)) {
- controller_entry_print_error(is_entry, global->main->error, cache->action, F_status_set_fine(status), "controller_rules_increase", F_true, global->thread);
+ controller_entry_print_error(is_entry, global.main->error, cache->action, F_status_set_fine(status), "controller_rules_increase", F_true, global.thread);
return status;
}
id_rule_name[entry_action->parameters.array[0].used] = f_path_separator_s[0];
id_rule_name[id_rule_length] = 0;
- status_lock = controller_lock_read(is_entry, global->thread, &global->thread->lock.rule);
+ status_lock = controller_lock_read(is_entry, global.thread, &global.thread->lock.rule);
if (F_status_is_error(status_lock)) {
- controller_lock_print_error_critical(global->main->error, F_status_set_fine(status_lock), F_true, global->thread);
+ controller_lock_print_error_critical(global.main->error, F_status_set_fine(status_lock), F_true, global.thread);
break;
}
- status = controller_rule_find(alias_rule, global->setting->rules, 0);
+ status = controller_rule_find(alias_rule, global.setting->rules, 0);
- f_thread_unlock(&global->thread->lock.rule);
+ f_thread_unlock(&global.thread->lock.rule);
- if (global->main->parameters[controller_parameter_simulate_e].result == f_console_result_found_e || global->main->error.verbosity == f_console_verbosity_verbose_e || global->main->error.verbosity == f_console_verbosity_debug_e || (entry->show == controller_entry_show_init_e && entry_action->type != controller_entry_action_type_consider_e)) {
- if (global->main->output.verbosity != f_console_verbosity_quiet_e) {
- controller_lock_print(global->main->output.to, global->thread);
+ if (global.main->parameters[controller_parameter_simulate_e].result == f_console_result_found_e || global.main->error.verbosity == f_console_verbosity_verbose_e || global.main->error.verbosity == f_console_verbosity_debug_e || (entry->show == controller_entry_show_init_e && entry_action->type != controller_entry_action_type_consider_e)) {
+ if (global.main->output.verbosity != f_console_verbosity_quiet_e) {
+ controller_lock_print(global.main->output.to, global.thread);
- fl_print_format("%c%s %s item rule ", global->main->output.to.stream, f_string_eol_s[0], entry_action->type == controller_entry_action_type_consider_e ? "Considering" : "Processing", is_entry ? controller_entry_s : controller_exit_s);
- fl_print_format("'%[%Q%]'", global->main->output.to.stream, global->main->context.set.title, alias_rule, global->main->context.set.title);
+ fl_print_format("%c%s %s item rule ", global.main->output.to.stream, f_string_eol_s[0], entry_action->type == controller_entry_action_type_consider_e ? "Considering" : "Processing", is_entry ? controller_entry_s : controller_exit_s);
+ fl_print_format("'%[%Q%]'", global.main->output.to.stream, global.main->context.set.title, alias_rule, global.main->context.set.title);
- if (entry->show == controller_entry_show_init_e && global->main->parameters[controller_parameter_simulate_e].result == f_console_result_none_e) {
- fl_print_format(" [%[%s%]]", global->main->output.to.stream, global->main->context.set.notable, entry_action->code == controller_entry_rule_code_asynchronous_d ? controller_asynchronous_s : controller_synchronous_s, global->main->context.set.notable);
+ if (entry->show == controller_entry_show_init_e && global.main->parameters[controller_parameter_simulate_e].result == f_console_result_none_e) {
+ fl_print_format(" [%[%s%]]", global.main->output.to.stream, global.main->context.set.notable, entry_action->code == controller_entry_rule_code_asynchronous_d ? controller_asynchronous_s : controller_synchronous_s, global.main->context.set.notable);
if (entry_action->code == controller_entry_rule_code_wait_d) {
- fl_print_format(" [%[%s%]]", global->main->output.to.stream, global->main->context.set.notable, controller_wait_s, global->main->context.set.notable);
+ fl_print_format(" [%[%s%]]", global.main->output.to.stream, global.main->context.set.notable, controller_wait_s, global.main->context.set.notable);
}
if (entry_action->code == controller_entry_rule_code_require_d) {
- fl_print_format(" [%[%s%]]", global->main->output.to.stream, global->main->context.set.notable, controller_required_s, global->main->context.set.notable);
+ fl_print_format(" [%[%s%]]", global.main->output.to.stream, global.main->context.set.notable, controller_required_s, global.main->context.set.notable);
}
}
- fl_print_format(".%c", global->main->output.to.stream, f_string_eol_s[0]);
+ fl_print_format(".%c", global.main->output.to.stream, f_string_eol_s[0]);
- controller_unlock_print_flush(global->main->output.to, global->thread);
+ controller_unlock_print_flush(global.main->output.to, global.thread);
}
}
- if (!controller_thread_is_enabled(is_entry, global->thread)) break;
+ if (!controller_thread_is_enabled(is_entry, global.thread)) break;
// the rule is not yet loaded, ensure that it is loaded.
if (status != F_true) {
memcpy(cache_name_item, cache->action.name_item.string, cache->action.name_item.used);
memcpy(cache_name_file, cache->action.name_file.string, cache->action.name_file.used);
- status_lock = controller_lock_write(is_entry, global->thread, &global->thread->lock.rule);
+ status_lock = controller_lock_write(is_entry, global.thread, &global.thread->lock.rule);
if (F_status_is_fine(status_lock)) {
- status = controller_rule_read(is_entry, alias_rule, *global, cache, entry, &global->setting->rules.array[global->setting->rules.used]);
+ status = controller_rule_read(global, is_entry, alias_rule, cache, entry, &global.setting->rules.array[global.setting->rules.used]);
}
// restore cache.
cache->action.line_item = cache_line_item;
if (F_status_is_error(status_lock)) {
- controller_lock_print_error_critical(global->main->error, F_status_set_fine(status_lock), F_false, global->thread);
+ controller_lock_print_error_critical(global.main->error, F_status_set_fine(status_lock), F_false, global.thread);
break;
}
- if (F_status_set_fine(status) == F_interrupt || !controller_thread_is_enabled(is_entry, global->thread)) {
- f_thread_unlock(&global->thread->lock.rule);
+ if (F_status_set_fine(status) == F_interrupt || !controller_thread_is_enabled(is_entry, global.thread)) {
+ f_thread_unlock(&global.thread->lock.rule);
break;
}
if (F_status_is_error(status)) {
- if (global->main->error.verbosity != f_console_verbosity_quiet_e) {
- controller_lock_print(global->main->error.to, global->thread);
+ if (global.main->error.verbosity != f_console_verbosity_quiet_e) {
+ controller_lock_print(global.main->error.to, global.thread);
- controller_entry_print_error_cache(is_entry, global->main->error, cache->action);
+ controller_entry_print_error_cache(is_entry, global.main->error, cache->action);
- controller_unlock_print_flush(global->main->error.to, global->thread);
+ controller_unlock_print_flush(global.main->error.to, global.thread);
}
// Designate the action as failed.
entry_action->status = F_status_set_error(F_failure);
- if (global->main->parameters[controller_parameter_simulate_e].result == f_console_result_none_e) {
- f_thread_unlock(&global->thread->lock.rule);
+ if (global.main->parameters[controller_parameter_simulate_e].result == f_console_result_none_e) {
+ f_thread_unlock(&global.thread->lock.rule);
if (entry_action->code & controller_entry_rule_code_require_d) {
return F_status_set_error(F_require);
}
}
else {
- ++global->setting->rules.used;
+ ++global.setting->rules.used;
}
- f_thread_unlock(&global->thread->lock.rule);
+ f_thread_unlock(&global.thread->lock.rule);
}
if (F_status_is_error_not(status)) {
options_force = 0;
options_process = 0;
- if (global->main->parameters[controller_parameter_simulate_e].result == f_console_result_found_e) {
+ if (global.main->parameters[controller_parameter_simulate_e].result == f_console_result_found_e) {
options_process |= controller_process_option_simulate_d;
}
options_process |= controller_process_option_wait_d;
}
- if (global->main->parameters[controller_parameter_validate_e].result == f_console_result_found_e) {
+ if (global.main->parameters[controller_parameter_validate_e].result == f_console_result_found_e) {
options_process |= controller_process_option_validate_d;
}
if (entry_action->code & controller_entry_rule_code_asynchronous_d) {
- if (global->main->parameters[controller_parameter_validate_e].result == f_console_result_none_e) {
+ if (global.main->parameters[controller_parameter_validate_e].result == f_console_result_none_e) {
options_force |= controller_process_option_asynchronous_d;
}
options_process |= controller_process_option_asynchronous_d;
}
- status = controller_rule_process_begin(options_force, alias_rule, controller_entry_action_type_to_rule_action_type(entry_action->type), options_process, is_entry ? controller_process_type_entry_e : controller_process_type_exit_e, stack, *global, *cache);
+ status = controller_rule_process_begin(global, options_force, alias_rule, controller_entry_action_type_to_rule_action_type(entry_action->type), options_process, is_entry ? controller_process_type_entry_e : controller_process_type_exit_e, stack, *cache);
if (F_status_set_fine(status) == F_memory_not || status == F_child || F_status_set_fine(status) == F_interrupt) {
break;
}
- if (F_status_is_error(status) && global->main->parameters[controller_parameter_simulate_e].result == f_console_result_none_e && (entry_action->code & controller_entry_rule_code_require_d)) {
+ if (F_status_is_error(status) && global.main->parameters[controller_parameter_simulate_e].result == f_console_result_none_e && (entry_action->code & controller_entry_rule_code_require_d)) {
return F_status_set_error(F_require);
}
}
}
else if (entry_action->type == controller_entry_action_type_execute_e) {
- if (global->main->parameters[controller_parameter_simulate_e].result == f_console_result_found_e || global->main->error.verbosity == f_console_verbosity_verbose_e || global->main->error.verbosity == f_console_verbosity_debug_e || entry->show == controller_entry_show_init_e) {
- if (global->main->output.verbosity != f_console_verbosity_quiet_e) {
- controller_lock_print(global->main->output.to, global->thread);
+ if (global.main->parameters[controller_parameter_simulate_e].result == f_console_result_found_e || global.main->error.verbosity == f_console_verbosity_verbose_e || global.main->error.verbosity == f_console_verbosity_debug_e || entry->show == controller_entry_show_init_e) {
+ if (global.main->output.verbosity != f_console_verbosity_quiet_e) {
+ controller_lock_print(global.main->output.to, global.thread);
- fl_print_format("%c%s is executing '", global->main->output.to.stream, f_string_eol_s[0], is_entry ? controller_entry_s : controller_exit_s);
+ fl_print_format("%c%s is executing '", global.main->output.to.stream, f_string_eol_s[0], is_entry ? controller_entry_s : controller_exit_s);
for (f_array_length_t k = 0; k < entry_action->parameters.used; ++k) {
- fl_print_format("%[%Q%]", global->main->output.to.stream, global->main->context.set.title, entry_action->parameters.array[k], global->main->context.set.title);
+ fl_print_format("%[%Q%]", global.main->output.to.stream, global.main->context.set.title, entry_action->parameters.array[k], global.main->context.set.title);
if (k + 1 < entry_action->parameters.used) {
- f_print_character(f_string_space_s[0], global->main->output.to.stream);
+ f_print_character(f_string_space_s[0], global.main->output.to.stream);
}
} // for
- fl_print_format("'.%c", global->main->output.to.stream, f_string_eol_s[0]);
+ fl_print_format("'.%c", global.main->output.to.stream, f_string_eol_s[0]);
- controller_unlock_print_flush(global->main->output.to, global->thread);
+ controller_unlock_print_flush(global.main->output.to, global.thread);
}
}
- if (global->main->parameters[controller_parameter_simulate_e].result == f_console_result_found_e) {
+ if (global.main->parameters[controller_parameter_simulate_e].result == f_console_result_found_e) {
return F_execute;
}
- controller_thread_process_cancel(is_entry, is_entry ? controller_thread_cancel_execute_e : controller_thread_cancel_exit_execute_e, global, process);
+ controller_thread_process_cancel(global, is_entry, is_entry ? controller_thread_cancel_execute_e : controller_thread_cancel_exit_execute_e, process);
int result = 0;
int option = FL_execute_parameter_option_path_d;
if (F_status_is_error(status)) {
if (F_status_set_fine(status) == F_file_found_not) {
- if (global->main->error.verbosity != f_console_verbosity_quiet_e) {
- controller_lock_print(global->main->error.to, global->thread);
+ if (global.main->error.verbosity != f_console_verbosity_quiet_e) {
+ controller_lock_print(global.main->error.to, global.thread);
- fl_print_format("%c%[%SExecution failed, unable to find program or script '%]", global->main->error.to.stream, f_string_eol_s[0], global->main->error.context, global->main->error.prefix ? global->main->error.prefix : f_string_empty_s, global->main->error.context);
- fl_print_format("%[%Q%]", global->main->error.to.stream, global->main->error.notable, entry_action->parameters.array[0], global->main->error.notable);
- fl_print_format("%['.%]%c", global->main->error.to.stream, global->main->error.context, global->main->error.context, f_string_eol_s[0]);
+ fl_print_format("%c%[%SExecution failed, unable to find program or script '%]", global.main->error.to.stream, f_string_eol_s[0], global.main->error.context, global.main->error.prefix ? global.main->error.prefix : f_string_empty_s, global.main->error.context);
+ fl_print_format("%[%Q%]", global.main->error.to.stream, global.main->error.notable, entry_action->parameters.array[0], global.main->error.notable);
+ fl_print_format("%['.%]%c", global.main->error.to.stream, global.main->error.context, global.main->error.context, f_string_eol_s[0]);
- controller_entry_print_error_cache(is_entry, global->main->error, cache->action);
+ controller_entry_print_error_cache(is_entry, global.main->error, cache->action);
- controller_unlock_print_flush(global->main->error.to, global->thread);
+ controller_unlock_print_flush(global.main->error.to, global.thread);
}
}
else {
- controller_entry_print_error(is_entry, global->main->error, cache->action, F_status_set_fine(status), "fll_execute_into", F_true, global->thread);
+ controller_entry_print_error(is_entry, global.main->error, cache->action, F_status_set_fine(status), "fll_execute_into", F_true, global.thread);
}
return F_status_set_error(F_execute);
}
else if (result != 0) {
- if (global->main->error.verbosity != f_console_verbosity_quiet_e) {
- controller_lock_print(global->main->error.to, global->thread);
+ if (global.main->error.verbosity != f_console_verbosity_quiet_e) {
+ controller_lock_print(global.main->error.to, global.thread);
- fl_print_format("%c%[%SExecution failed with return value of '%]", global->main->error.to.stream, f_string_eol_s[0], global->main->error.context, global->main->error.prefix ? global->main->error.prefix : f_string_empty_s, global->main->error.context);
- fl_print_format("%[%i%]", global->main->error.to.stream, global->main->error.notable, result, global->main->error.notable);
- fl_print_format("$['.%]%c", global->main->error.to.stream, global->main->error.context, global->main->error.context, f_string_eol_s[0]);
+ fl_print_format("%c%[%SExecution failed with return value of '%]", global.main->error.to.stream, f_string_eol_s[0], global.main->error.context, global.main->error.prefix ? global.main->error.prefix : f_string_empty_s, global.main->error.context);
+ fl_print_format("%[%i%]", global.main->error.to.stream, global.main->error.notable, result, global.main->error.notable);
+ fl_print_format("$['.%]%c", global.main->error.to.stream, global.main->error.context, global.main->error.context, f_string_eol_s[0]);
- controller_entry_print_error_cache(is_entry, global->main->error, cache->action);
+ controller_entry_print_error_cache(is_entry, global.main->error, cache->action);
- controller_unlock_print_flush(global->main->error.to, global->thread);
+ controller_unlock_print_flush(global.main->error.to, global.thread);
}
return F_status_set_error(F_execute);
if (entry_action->code == controller_entry_timeout_code_kill_d) {
entry->timeout_kill = entry_action->number;
- controller_entry_preprocess_print_simulate_setting_value(is_entry, *global, controller_timeout_s, controller_kill_s, entry->items.array[global->setting->failsafe_item_id].name, suffix);
+ controller_entry_preprocess_print_simulate_setting_value(global, is_entry, controller_timeout_s, controller_kill_s, entry->items.array[global.setting->failsafe_item_id].name, suffix);
}
else if (entry_action->code == controller_entry_timeout_code_start_d) {
entry->timeout_start = entry_action->number;
- controller_entry_preprocess_print_simulate_setting_value(is_entry, *global, controller_timeout_s, controller_start_s, entry->items.array[global->setting->failsafe_item_id].name, suffix);
+ controller_entry_preprocess_print_simulate_setting_value(global, is_entry, controller_timeout_s, controller_start_s, entry->items.array[global.setting->failsafe_item_id].name, suffix);
}
else if (entry_action->code == controller_entry_timeout_code_stop_d) {
entry->timeout_stop = entry_action->number;
- controller_entry_preprocess_print_simulate_setting_value(is_entry, *global, controller_timeout_s, controller_stop_s, entry->items.array[global->setting->failsafe_item_id].name, suffix);
+ controller_entry_preprocess_print_simulate_setting_value(global, is_entry, controller_timeout_s, controller_stop_s, entry->items.array[global.setting->failsafe_item_id].name, suffix);
}
}
else if (entry_action->type == controller_entry_action_type_failsafe_e) {
if (failsafe) {
- if (global->main->warning.verbosity == f_console_verbosity_debug_e) {
- controller_lock_print(global->main->warning.to, global->thread);
+ if (global.main->warning.verbosity == f_console_verbosity_debug_e) {
+ controller_lock_print(global.main->warning.to, global.thread);
- fl_print_format("%c%[%SFailsafe may not be specified when running in failsafe, ignoring.%]%c", global->main->warning.to.stream, f_string_eol_s[0], global->main->warning.context, global->main->warning.prefix ? global->main->warning.prefix : f_string_empty_s, global->main->warning.context, f_string_eol_s[0]);
+ fl_print_format("%c%[%SFailsafe may not be specified when running in failsafe, ignoring.%]%c", global.main->warning.to.stream, f_string_eol_s[0], global.main->warning.context, global.main->warning.prefix, global.main->warning.context, f_string_eol_s[0]);
- controller_entry_print_error_cache(is_entry, global->main->warning, cache->action);
+ controller_entry_print_error_cache(is_entry, global.main->warning, cache->action);
- controller_unlock_print_flush(global->main->warning.to, global->thread);
+ controller_unlock_print_flush(global.main->warning.to, global.thread);
}
}
else {
if (entry_action->number == 0 || entry_action->number >= entry->items.used) {
// This should not happen if the pre-process is working as designed, but in case it doesn't, return a critical error to prevent infinite recursion and similar errors.
- if (global->main->error.verbosity != f_console_verbosity_quiet_e) {
- controller_lock_print(global->main->error.to, global->thread);
+ if (global.main->error.verbosity != f_console_verbosity_quiet_e) {
+ controller_lock_print(global.main->error.to, global.thread);
- fl_print_format("%c%[%SInvalid %s item index '%]", global->main->error.to.stream, f_string_eol_s[0], global->main->error.context, global->main->error.prefix ? global->main->error.prefix : f_string_empty_s, is_entry ? controller_entry_s : controller_exit_s, global->main->error.context);
- fl_print_format("%[%un%]", global->main->error.to.stream, global->main->error.notable, entry_action->number, global->main->error.notable);
- fl_print_format("%[' detected.%]%c", global->main->error.to.stream, global->main->error.context, global->main->error.context, f_string_eol_s[0]);
+ fl_print_format("%c%[%SInvalid %s item index '%]", global.main->error.to.stream, f_string_eol_s[0], global.main->error.context, global.main->error.prefix ? global.main->error.prefix : f_string_empty_s, is_entry ? controller_entry_s : controller_exit_s, global.main->error.context);
+ fl_print_format("%[%un%]", global.main->error.to.stream, global.main->error.notable, entry_action->number, global.main->error.notable);
+ fl_print_format("%[' detected.%]%c", global.main->error.to.stream, global.main->error.context, global.main->error.context, f_string_eol_s[0]);
- controller_entry_print_error_cache(is_entry, global->main->error, cache->action);
+ controller_entry_print_error_cache(is_entry, global.main->error, cache->action);
- controller_unlock_print_flush(global->main->error.to, global->thread);
+ controller_unlock_print_flush(global.main->error.to, global.thread);
}
return F_status_is_error(F_critical);
}
else {
- global->setting->failsafe_enabled = F_true;
- global->setting->failsafe_item_id = entry_action->number;
+ global.setting->failsafe_enabled = F_true;
+ global.setting->failsafe_item_id = entry_action->number;
- controller_entry_preprocess_print_simulate_setting_value(is_entry, *global, controller_failsafe_s, 0, entry->items.array[global->setting->failsafe_item_id].name, 0);
+ controller_entry_preprocess_print_simulate_setting_value(global, is_entry, controller_failsafe_s, 0, entry->items.array[global.setting->failsafe_item_id].name, 0);
}
}
}
status = controller_dynamic_append_terminated(entry->items.array[cache->ats.array[at_i]].name, &cache->action.name_item);
if (F_status_is_error(status)) {
- controller_entry_print_error(is_entry, global->main->error, cache->action, F_status_set_fine(status), "controller_dynamic_append_terminated", F_true, global->thread);
+ controller_entry_print_error(is_entry, global.main->error, cache->action, F_status_set_fine(status), "controller_dynamic_append_terminated", F_true, global.thread);
break;
}
}
} // while
- if (!controller_thread_is_enabled(is_entry, global->thread)) {
+ if (!controller_thread_is_enabled(is_entry, global.thread)) {
return F_status_set_error(F_interrupt);
}
}
// check to see if any required processes failed, but do not do this if already operating in failsafe.
- if (F_status_is_error_not(status) && !failsafe && global->main->parameters[controller_parameter_validate_e].result == f_console_result_none_e) {
- const f_status_t status_wait = controller_rule_wait_all(is_entry, *global, F_true, 0);
+ if (F_status_is_error_not(status) && !failsafe && global.main->parameters[controller_parameter_validate_e].result == f_console_result_none_e) {
+ const f_status_t status_wait = controller_rule_wait_all(global, is_entry, F_true, 0);
if (F_status_is_error(status_wait)) {
return status_wait;
}
}
- if ((global->main->parameters[controller_parameter_simulate_e].result == f_console_result_found_e && global->main->error.verbosity != f_console_verbosity_quiet_e) || global->main->error.verbosity == f_console_verbosity_verbose_e) {
- controller_lock_print(global->main->output.to, global->thread);
+ if ((global.main->parameters[controller_parameter_simulate_e].result == f_console_result_found_e && global.main->error.verbosity != f_console_verbosity_quiet_e) || global.main->error.verbosity == f_console_verbosity_verbose_e) {
+ controller_lock_print(global.main->output.to, global.thread);
- fl_print_format("%cDone processing %s item '", global->main->output.to.stream, f_string_eol_s[0], is_entry ? controller_entry_s : controller_exit_s);
- fl_print_format("%[%s%]", global->main->output.to.stream, global->main->context.set.title, controller_main_s, global->main->context.set.title);
- fl_print_format("'.%c", global->main->output.to.stream, f_string_eol_s[0]);
+ fl_print_format("%cDone processing %s item '", global.main->output.to.stream, f_string_eol_s[0], is_entry ? controller_entry_s : controller_exit_s);
+ fl_print_format("%[%s%]", global.main->output.to.stream, global.main->context.set.title, controller_main_s, global.main->context.set.title);
+ fl_print_format("'.%c", global.main->output.to.stream, f_string_eol_s[0]);
// failsafe should not print the extra newline because the failure exit from controller_main should handle this.
if (!failsafe) {
- f_print_terminated(f_string_eol_s, global->main->output.to.stream);
+ f_print_terminated(f_string_eol_s, global.main->output.to.stream);
}
- controller_unlock_print_flush(global->main->output.to, global->thread);
+ controller_unlock_print_flush(global.main->output.to, global.thread);
}
return status;
#endif // _di_controller_entry_process_
#ifndef _di_controller_entry_read_
- f_status_t controller_entry_read(const bool is_entry, controller_global_t global, controller_cache_t *cache) {
+ f_status_t controller_entry_read(const controller_global_t global, const bool is_entry, controller_cache_t * const cache) {
f_status_t status = F_none;
cache->action.name_item.used = 0;
if (is_entry) {
- status = controller_file_load(F_true, controller_entries_s, global.setting->name_entry, controller_entry_s, controller_entries_s_length, controller_entry_s_length, global, cache);
+ status = controller_file_load(global, F_true, controller_entries_s, global.setting->name_entry, controller_entry_s, controller_entries_s_length, controller_entry_s_length, cache);
}
else {
- status = controller_file_load(F_false, controller_exits_s, global.setting->name_entry, controller_exit_s, controller_exits_s_length, controller_exit_s_length, global, cache);
+ status = controller_file_load(global, F_false, controller_exits_s, global.setting->name_entry, controller_exit_s, controller_exits_s_length, controller_exit_s_length, cache);
if (status == F_file_found_not) {
return F_file_found_not;
}
}
else if (fl_string_dynamic_compare_string(controller_setting_s, cache->action.name_item, controller_setting_s_length) == F_equal_to) {
- status = controller_entry_settings_read(is_entry, *range, global, cache);
+ status = controller_entry_settings_read(global, is_entry, *range, cache);
continue;
}
break;
}
- status = controller_entry_actions_read(is_entry, *range, global, cache, &entry->items.array[at].actions);
+ status = controller_entry_actions_read(global, is_entry, *range, cache, &entry->items.array[at].actions);
if (F_status_is_error(status)) {
if (F_status_set_fine(status) != F_interrupt) {
#endif // _di_controller_entry_read_
#ifndef _di_controller_entry_settings_read_
- f_status_t controller_entry_settings_read(const bool is_entry, const f_string_range_t content_range, controller_global_t global, controller_cache_t *cache) {
+ f_status_t controller_entry_settings_read(const controller_global_t global, const bool is_entry, const f_string_range_t content_range, controller_cache_t * const cache) {
f_status_t status = F_none;
if (F_status_is_error(status)) {
controller_entry_print_error(is_entry, global.main->error, cache->action, F_status_set_fine(status), "f_fss_count_lines", F_true, global.thread);
+
break;
}
if (F_status_is_error(status)) {
controller_entry_print_error(is_entry, global.main->error, cache->action, F_status_set_fine(status), "controller_dynamic_rip_nulless_terminated", F_true, global.thread);
+
break;
}
- if (is_entry && fl_string_dynamic_compare_string(controller_mode_s, cache->action.name_action, controller_mode_s_length) == F_equal_to) {
- if (cache->content_actions.array[i].used < 0 || cache->content_actions.array[i].used > 1) {
- controller_entry_settings_read_print_setting_requires_exactly(is_entry, global, *cache, 1);
+ if (is_entry && fl_string_dynamic_compare_string(controller_control_s, cache->action.name_action, controller_control_s_length) == F_equal_to) {
+ if (cache->content_actions.array[i].used != 1) {
+ controller_entry_settings_read_print_setting_requires_exactly(global, is_entry, *cache, 1);
+
+ continue;
+ }
+
+ // @todo swap the generic with the path_control so that this can then be swapped again using canonical.
+ cache->action.generic.used = 0;
+ global.setting->path_control.used = 0;
+
+ status = controller_dynamic_rip_nulless_terminated(cache->buffer_file, cache->content_actions.array[i].array[0], &global.setting->path_control);
+
+ if (F_status_is_error(status)) {
+ controller_entry_print_error(is_entry, global.main->error, cache->action, F_status_set_fine(status), "controller_dynamic_rip_nulless_terminated", F_true, global.thread);
+
+ global.setting->path_control.used = 0;
+
+ break;
+ }
+
+ if (f_path_is_relative(global.setting->path_control.string, global.setting->path_control.used) == F_true) {
+
+ // Use the PID file path for creating a relative path to the control socket.
+ status = f_file_name_directory(global.setting->path_pid.string, global.setting->path_pid.used, &cache->action.generic);
+
+ if (F_status_is_error(status)) {
+ controller_entry_print_error(is_entry, global.main->error, cache->action, F_status_set_fine(status), "f_file_name_directory", F_true, global.thread);
+
+ global.setting->path_control.used = 0;
+
+ break;
+ }
+
+ status = f_string_append(f_path_separator_s, 1, &cache->action.generic);
+
+ if (F_status_is_error(status)) {
+ controller_entry_print_error(is_entry, global.main->error, cache->action, F_status_set_fine(status), "f_string_dynamic_append", F_true, global.thread);
+
+ global.setting->path_control.used = 0;
+
+ break;
+ }
+
+ status = f_string_dynamic_append(global.setting->path_control, &cache->action.generic);
+
+ if (F_status_is_error(status)) {
+ controller_entry_print_error(is_entry, global.main->error, cache->action, F_status_set_fine(status), "f_string_dynamic_append", F_true, global.thread);
+
+ global.setting->path_control.used = 0;
+
+ break;
+ }
+ }
+ else {
+ status = f_string_dynamic_append(global.setting->path_control, &cache->action.generic);
+
+ if (F_status_is_error(status)) {
+ controller_entry_print_error(is_entry, global.main->error, cache->action, F_status_set_fine(status), "f_string_dynamic_append", F_true, global.thread);
+
+ global.setting->path_control.used = 0;
+
+ break;
+ }
+ }
+
+ status = f_string_dynamic_terminate_after(&cache->action.generic);
+
+ if (F_status_is_error(status)) {
+ controller_entry_print_error(is_entry, global.main->error, cache->action, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true, global.thread);
+
+ global.setting->path_control.used = 0;
+
+ break;
+ }
+
+ status = fll_path_canonical(cache->action.generic.string, &global.setting->path_control);
+
+ if (F_status_is_error(status)) {
+ controller_entry_print_error_file(is_entry, global.main->error, cache->action, F_status_set_fine(status), "fll_path_canonical", F_true, cache->action.generic.string, "analyze", fll_error_file_type_path_e, global.thread);
+
+ global.setting->path_control.used = 0;
+
+ continue;
+ }
+ }
+ else if (is_entry && fl_string_dynamic_compare_string(controller_control_group_s, cache->action.name_action, controller_control_group_s_length) == F_equal_to) {
+ gid_t number = 0;
+
+ status = controller_get_id_group(cache->buffer_file, cache->content_actions.array[i].array[0], cache, &number);
+
+ if (F_status_is_error(status)) {
+ status = F_status_set_fine(status);
+
+ if (status == F_exist_not) {
+ controller_entry_setting_read_print_error_with_range(is_entry, global.main->error, " has an invalid group", cache->content_actions.array[i].array[0], ", because no group was found by that name", global.thread, cache);
+ }
+ else if (status == F_number_too_large) {
+ controller_entry_setting_read_print_error_with_range(is_entry, global.main->error, " has an invalid group", cache->content_actions.array[i].array[0], ", because the given ID is too large", global.thread, cache);
+ }
+ else if (status == F_number) {
+ controller_entry_setting_read_print_error_with_range(is_entry, global.main->error, " has an invalid group", cache->content_actions.array[i].array[0], ", because the given ID is not a valid supported number", global.thread, cache);
+ }
+ else {
+ controller_entry_print_error(is_entry, global.main->error, cache->action, F_status_set_fine(status), "controller_get_id_group", F_true, global.thread);
+ }
+
+ continue;
+ }
+
+ global.setting->control_group = number;
+ }
+ else if (is_entry && fl_string_dynamic_compare_string(controller_control_mode_s, cache->action.name_action, controller_control_mode_s_length) == F_equal_to) {
+ mode_t mode = 0;
+ uint8_t replace = 0;
+ f_file_mode_t mode_file = f_file_mode_t_initialize;
+
+ cache->action.generic.used = 0;
+
+ status = controller_dynamic_rip_nulless_terminated(cache->buffer_file, cache->content_actions.array[i].array[0], &cache->action.generic);
+
+ if (F_status_is_error(status)) {
+ controller_entry_print_error(is_entry, global.main->error, cache->action, F_status_set_fine(status), "controller_dynamic_rip_nulless_terminated", F_true, global.thread);
+
+ break;
+ }
+
+ status = f_file_mode_from_string(cache->action.generic.string, global.main->umask, &mode_file, &replace);
+
+ if (F_status_is_error(status)) {
+ controller_entry_setting_read_print_error_with_range(is_entry, global.main->error, " has an unsupported mode", cache->content_actions.array[i].array[0], ", because the format is unknown or contains invalid data", global.thread, cache);
+
+ continue;
+ }
+
+ status = f_file_mode_to_mode(mode_file, &mode);
+
+ if (F_status_is_error(status)) {
+ controller_entry_print_error(is_entry, global.main->error, cache->action, F_status_set_fine(status), "f_file_mode_to_mode", F_true, global.thread);
+
+ continue;
+ }
+
+ global.setting->control_mode = mode;
+ }
+ else if (is_entry && fl_string_dynamic_compare_string(controller_control_user_s, cache->action.name_action, controller_control_user_s_length) == F_equal_to) {
+ uid_t number = 0;
+
+ status = controller_get_id_user(cache->buffer_file, cache->content_actions.array[i].array[0], cache, &number);
+
+ if (F_status_is_error(status)) {
+ status = F_status_set_fine(status);
+
+ if (status == F_exist_not) {
+ controller_entry_setting_read_print_error_with_range(is_entry, global.main->error, " has an invalid user", cache->content_actions.array[i].array[0], ", because no user was found by that name", global.thread, cache);
+ }
+ else if (status == F_number_too_large) {
+ controller_entry_setting_read_print_error_with_range(is_entry, global.main->error, " has an invalid user", cache->content_actions.array[i].array[0], ", because the given ID is too large", global.thread, cache);
+ }
+ else if (status == F_number) {
+ controller_entry_setting_read_print_error_with_range(is_entry, global.main->error, " has an invalid user", cache->content_actions.array[i].array[0], ", because the given ID is not a valid supported number", global.thread, cache);
+ }
+ else {
+ controller_entry_print_error(is_entry, global.main->error, cache->action, F_status_set_fine(status), "controller_get_id_user", F_true, global.thread);
+ }
+
+ continue;
+ }
+
+ global.setting->control_user = number;
+ }
+ else if (is_entry && fl_string_dynamic_compare_string(controller_mode_s, cache->action.name_action, controller_mode_s_length) == F_equal_to) {
+ if (cache->content_actions.array[i].used != 1) {
+ controller_entry_settings_read_print_setting_requires_exactly(global, is_entry, *cache, 1);
continue;
}
global.setting->mode = controller_setting_mode_program_e;
}
else {
- controller_entry_settings_read_print_setting_unknown_action_value(is_entry, global, *cache, i);
+ controller_entry_settings_read_print_setting_unknown_action_value(global, is_entry, *cache, i);
continue;
}
}
else if (fl_string_dynamic_compare_string(controller_pid_s, cache->action.name_action, controller_pid_s_length) == F_equal_to) {
- if (cache->content_actions.array[i].used < 0 || cache->content_actions.array[i].used > 1) {
- controller_entry_settings_read_print_setting_requires_exactly(is_entry, global, *cache, 1);
+ if (cache->content_actions.array[i].used != 1) {
+ controller_entry_settings_read_print_setting_requires_exactly(global, is_entry, *cache, 1);
continue;
}
entry->pid = controller_entry_pid_require_e;
}
else {
- controller_entry_settings_read_print_setting_unknown_action_value(is_entry, global, *cache, i);
+ controller_entry_settings_read_print_setting_unknown_action_value(global, is_entry, *cache, i);
continue;
}
}
else if (fl_string_dynamic_compare_string(controller_session_s, cache->action.name_action, controller_session_s_length) == F_equal_to) {
- if (cache->content_actions.array[i].used < 0 || cache->content_actions.array[i].used > 1) {
- controller_entry_settings_read_print_setting_requires_exactly(is_entry, global, *cache, 1);
+ if (cache->content_actions.array[i].used != 1) {
+ controller_entry_settings_read_print_setting_requires_exactly(global, is_entry, *cache, 1);
continue;
}
entry->session = controller_entry_session_same_e;
}
else {
- controller_entry_settings_read_print_setting_unknown_action_value(is_entry, global, *cache, i);
+ controller_entry_settings_read_print_setting_unknown_action_value(global, is_entry, *cache, i);
continue;
}
}
else if (fl_string_dynamic_compare_string(controller_show_s, cache->action.name_action, controller_show_s_length) == F_equal_to) {
- if (cache->content_actions.array[i].used < 0 || cache->content_actions.array[i].used > 1) {
- controller_entry_settings_read_print_setting_requires_exactly(is_entry, global, *cache, 1);
+ if (cache->content_actions.array[i].used != 1) {
+ controller_entry_settings_read_print_setting_requires_exactly(global, is_entry, *cache, 1);
continue;
}
entry->show = controller_entry_show_init_e;
}
else {
- controller_entry_settings_read_print_setting_unknown_action_value(is_entry, global, *cache, i);
+ controller_entry_settings_read_print_setting_unknown_action_value(global, is_entry, *cache, i);
continue;
}
}
else {
if (global.main->warning.verbosity == f_console_verbosity_debug_e) {
- controller_entry_settings_read_print_setting_unknown_action(is_entry, global, *cache);
+ controller_entry_settings_read_print_setting_unknown_action(global, is_entry, *cache);
}
continue;
}
} // for
+
+ return status;
}
#endif // _di_controller_entry_settings_read_
/**
* Read the entry list, extracting all items and values.
*
+ * @param global
+ * The global data.
* @param is_entry
* If TRUE, then this loads as an entry.
* If FALSE, then this loads as an exit.
* @param content_range
* The range in the list buffer representing the content.
- * @param global
- * The global data.
* @param cache
* A structure for containing and caching relevant data.
* @param actions
* @see fll_fss_extended_read()
*/
#ifndef _di_controller_entry_actions_read_
- extern f_status_t controller_entry_actions_read(const bool is_entry, const f_string_range_t content_range, controller_global_t global, controller_cache_t *cache, controller_entry_actions_t *actions) F_attribute_visibility_internal_d;
+ extern f_status_t controller_entry_actions_read(const controller_global_t global, const bool is_entry, const f_string_range_t content_range, controller_cache_t * const cache, controller_entry_actions_t *actions) F_attribute_visibility_internal_d;
#endif // _di_controller_entry_actions_read_
/**
* Pre-process all items for the loaded entry.
*
+ * @param global
+ * The global data.
* @param is_entry
* If TRUE, then this operate as an entry.
* If FALSE, then this operate as an exit.
- * @param global
- * The global data.
* @param cache
* The main/global cache to use.
*
* @see f_string_dynamic_terminate_after()
*/
#ifndef _di_controller_entry_preprocess_
- extern f_status_t controller_entry_preprocess(const bool is_entry, controller_global_t global, controller_cache_t *cache) F_attribute_visibility_internal_d;
+ extern f_status_t controller_entry_preprocess(const controller_global_t global, const bool is_entry, controller_cache_t * const cache) F_attribute_visibility_internal_d;
#endif // _di_controller_entry_preprocess_
/**
* Process (execute) all Items for the loaded Entry or Exit.
*
+ * @param global
+ * The global data.
* @param failsafe
* If TRUE, operate in failsafe mode (starts at designated failsafe Item).
* If FALSE, operate in normal mode (starts at "main" Item).
* @param is_entry
* If TRUE, then this operate as an entry.
* If FALSE, then this operate as an exit.
- * @param global
- * The global data.
* @param cache
* The main/global cache to use.
*
* @see controller_dynamic_append_terminated()
*/
#ifndef _di_controller_entry_process_
- extern f_status_t controller_entry_process(const bool failsafe, const bool is_entry, controller_global_t *global, controller_cache_t *cache) F_attribute_visibility_internal_d;
+ extern f_status_t controller_entry_process(const controller_global_t global, const bool failsafe, const bool is_entry, controller_cache_t * const cache) F_attribute_visibility_internal_d;
#endif // _di_controller_entry_process_
/**
* Read the entry, extracting all lists.
*
+ * @param global
+ * The global data.
* @param is_entry
* If TRUE, then this loads as an entry.
* If FALSE, then this loads as an exit.
- * @param global
- * The global data.
* @param cache
* The cache for the specific thread.
* This should be the cache global.thread->asynchronouss.array[global.id].cache.
* @see fll_fss_basic_list_read()
*/
#ifndef _di_controller_entry_read_
- extern f_status_t controller_entry_read(const bool is_entry, controller_global_t global, controller_cache_t *cache) F_attribute_visibility_internal_d;
+ extern f_status_t controller_entry_read(const controller_global_t global, const bool is_entry, controller_cache_t * const cache) F_attribute_visibility_internal_d;
#endif // _di_controller_entry_read_
/**
* Read the entry settings, loading all settings.
*
+ * @param global
+ * The global data.
* @param is_entry
* If TRUE, then this loads as an entry.
* If FALSE, then this loads as an exit.
* @param content_range
* The range in the list buffer representing the content.
- * @param global
- * The global data.
* @param cache
* A structure for containing and caching relevant data.
*/
#ifndef _di_controller_entry_settings_read_
- extern f_status_t controller_entry_settings_read(const bool is_entry, const f_string_range_t content_range, controller_global_t global, controller_cache_t *cache) F_attribute_visibility_internal_d;
+ extern f_status_t controller_entry_settings_read(const controller_global_t global, const bool is_entry, const f_string_range_t content_range, controller_cache_t * const cache) F_attribute_visibility_internal_d;
#endif // _di_controller_entry_settings_read_
#ifdef __cplusplus
#endif // _di_controller_entry_action_parameters_print_
#ifndef _di_controller_entry_preprocess_print_simulate_setting_value_
- void controller_entry_preprocess_print_simulate_setting_value(const bool is_entry, const controller_global_t global, const f_string_t name, const f_string_t name_sub, const f_string_static_t value, const f_string_t suffix) {
+ void controller_entry_preprocess_print_simulate_setting_value(const controller_global_t global, const bool is_entry, const f_string_t name, const f_string_t name_sub, const f_string_static_t value, const f_string_t suffix) {
if (global.main->error.verbosity != f_console_verbosity_debug_e && !(global.main->error.verbosity == f_console_verbosity_verbose_e && global.main->parameters[controller_parameter_simulate_e].result == f_console_result_found_e)) {
return;
}
#endif // _di_controller_entry_print_error_cache_
+#ifndef _di_controller_entry_print_error_file_
+ void controller_entry_print_error_file(const bool is_entry, const fl_print_t print, const controller_cache_action_t cache, const f_status_t status, const f_string_t function, const bool fallback, const f_string_t name, const f_string_t operation, const uint8_t type, controller_thread_t *thread) {
+
+ if (print.verbosity == f_console_verbosity_quiet_e) return;
+ if (status == F_interrupt) return;
+
+ // fll_error_file_print() automatically locks, so manually handle only the mutex locking and flushing rather than calling controller_lock_print().
+ f_thread_mutex_lock(&thread->lock.print);
+
+ fll_error_file_print(print, status, function, fallback, name, operation, type);
+
+ flockfile(print.to.stream);
+
+ controller_entry_print_error_cache(is_entry, print, cache);
+
+ controller_unlock_print_flush(print.to, thread);
+ }
+#endif // _di_controller_entry_print_error_file_
+
+#ifndef _di_controller_entry_setting_read_print_error_with_range_
+ void controller_entry_setting_read_print_error_with_range(const bool is_entry, const fl_print_t print, const f_string_t before, const f_string_range_t range, const f_string_t after, controller_thread_t * const thread, controller_cache_t * const cache) {
+
+ if (print.verbosity == f_console_verbosity_quiet_e) return;
+
+ controller_lock_print(print.to, thread);
+
+ fl_print_format("%c%[%S%s setting%S '%]", print.to.stream, f_string_eol_s[0], print.context, print.prefix, is_entry ? "Entry" : "Exit", before, print.context);
+ fl_print_format("%[%/Q%]", print.to.stream, print.notable, cache->buffer_file, range, print.notable);
+ fl_print_format("%['%S.%]%c", print.to.stream, print.context, after, print.context, f_string_eol_s[0]);
+
+ controller_entry_print_error_cache(is_entry, print, cache->action);
+
+ controller_unlock_print_flush(print.to, thread);
+ }
+#endif // _di_controller_entry_setting_read_print_error_with_range_
+
#ifndef _di_controller_entry_settings_read_print_setting_requires_exactly_
- void controller_entry_settings_read_print_setting_requires_exactly(const bool is_entry, const controller_global_t global, const controller_cache_t cache, const f_number_unsigned_t total) {
+ void controller_entry_settings_read_print_setting_requires_exactly(const controller_global_t global, const bool is_entry, const controller_cache_t cache, const f_number_unsigned_t total) {
if (global.main->error.verbosity == f_console_verbosity_quiet_e) return;
#endif // _di_controller_entry_settings_read_print_setting_requires_exactly_
#ifndef _di_controller_entry_settings_read_print_setting_unknown_action_
- void controller_entry_settings_read_print_setting_unknown_action(const bool is_entry, const controller_global_t global, const controller_cache_t cache) {
+ void controller_entry_settings_read_print_setting_unknown_action(const controller_global_t global, const bool is_entry, const controller_cache_t cache) {
if (global.main->warning.verbosity != f_console_verbosity_debug_e) return;
#endif // _di_controller_entry_settings_read_print_setting_unknown_action_
#ifndef _di_controller_entry_settings_read_print_setting_unknown_action_value_
- void controller_entry_settings_read_print_setting_unknown_action_value(const bool is_entry, const controller_global_t global, const controller_cache_t cache, const f_array_length_t index) {
+ void controller_entry_settings_read_print_setting_unknown_action_value(const controller_global_t global, const bool is_entry, const controller_cache_t cache, const f_array_length_t index) {
if (global.main->warning.verbosity != f_console_verbosity_debug_e) return;
/**
* Print message regarding the population of a setting when in simulation or verbose mode.
*
+ * @param global
+ * The global data.
* @param is_entry
* If TRUE, then this operate as an entry.
* If FALSE, then this operate as an exit.
- * @param global
- * The global data.
* @param name
* The Object name of the setting being populated.
* @param name_sub
* An additional message to append at the end (before the final period).
*/
#ifndef _di_controller_entry_preprocess_print_simulate_setting_value_
- extern void controller_entry_preprocess_print_simulate_setting_value(const bool is_entry, const controller_global_t global, const f_string_t name, const f_string_t name_sub, const f_string_static_t value, const f_string_t suffix) F_attribute_visibility_internal_d;
+ extern void controller_entry_preprocess_print_simulate_setting_value(const controller_global_t global, const bool is_entry, const f_string_t name, const f_string_t name_sub, const f_string_static_t value, const f_string_t suffix) F_attribute_visibility_internal_d;
#endif // _di_controller_entry_preprocess_print_simulate_setting_value_
/**
#endif // _di_controller_entry_print_error_cache_
/**
- * Print a message for when an entry setting action has the incorrect number of parameters.
+ * Print the entry related file error, locking the print mutex during the print.
+ *
+ * @param is_entry
+ * If TRUE, then this loads as an entry.
+ * If FALSE, then this loads as an exit.
+ * @param print
+ * Designates how printing is to be performed.
+ * @param cache
+ * The action cache.
+ * @param status
+ * The status code to process.
+ * Make sure this has F_status_set_fine() called if the status code has any error or warning bits.
+ * @param function
+ * The name of the function where the error happened.
+ * Set to 0 to disable.
+ * @param fallback
+ * Set to F_true to print the fallback error message for unknown errors.
+ * @param name
+ * The name of the file or directory.
+ * @param operation
+ * The operation that fails, such as 'create' or 'access'.
+ * @param type
+ * A valid file type code from the fll_error_file_type enum.
+ * @param thread
+ * The thread data.
+ *
+ * @see fll_error_file_print()
+ * @see controller_entry_print_error_cache()
+ */
+#ifndef _di_controller_entry_print_error_file_
+ extern void controller_entry_print_error_file(const bool is_entry, const fl_print_t print, const controller_cache_action_t cache, const f_status_t status, const f_string_t function, const bool fallback, const f_string_t name, const f_string_t operation, const uint8_t type, controller_thread_t *thread) F_attribute_visibility_internal_d;
+#endif // _di_controller_entry_print_error_file_
+
+/**
+ * Print a message about an entry setting problem, with additional messages about the value.
+ *
+ * This is intended to be explicitly called by controller_entry_settings_read().
+ * This is intended only to be used for simple messages.
*
* @param is_entry
* If TRUE, then this loads as an entry.
* If FALSE, then this loads as an exit.
+ * @param print
+ * The error or warning output structure.
+ * @param before
+ * The string to add to the message being printed (before the value).
+ * @param range
+ * The range within the cache item buffer representing the value.
+ * @param after
+ * The string to add to the message being printed (after the value).
+ * @param thread
+ * The thread data.
+ * @param cache
+ * A structure for containing and caching relevant data.
+ *
+ * @see controller_entry_settings_read()
+ */
+#ifndef _di_controller_entry_setting_read_print_error_with_range_
+ extern void controller_entry_setting_read_print_error_with_range(const bool is_entry, const fl_print_t print, const f_string_t before, const f_string_range_t range, const f_string_t after, controller_thread_t * const thread, controller_cache_t * const cache) F_attribute_visibility_internal_d;
+#endif // _di_controller_entry_setting_read_print_error_with_range_
+
+/**
+ * Print a message for when an entry setting action has the incorrect number of parameters.
+ *
* @param global
* The global data.
+ * @param is_entry
+ * If TRUE, then this loads as an entry.
+ * If FALSE, then this loads as an exit.
* @param cache
* A structure for containing and caching relevant data.
* @param total
* The expected number of arguments.
*/
#ifndef _di_controller_entry_settings_read_print_setting_requires_exactly_
- extern void controller_entry_settings_read_print_setting_requires_exactly(const bool is_entry, const controller_global_t global, const controller_cache_t cache, const f_number_unsigned_t total) F_attribute_visibility_internal_d;
+ extern void controller_entry_settings_read_print_setting_requires_exactly(const controller_global_t global, const bool is_entry, const controller_cache_t cache, const f_number_unsigned_t total) F_attribute_visibility_internal_d;
#endif // _di_controller_entry_settings_read_print_setting_requires_exactly_
/**
* Print a message for when an entry setting action is unknown.
*
+ * @param global
+ * The global data.
* @param is_entry
* If TRUE, then this loads as an entry.
* If FALSE, then this loads as an exit.
- * @param global
- * The global data.
* @param cache
* A structure for containing and caching relevant data.
*/
#ifndef _di_controller_entry_settings_read_print_setting_unknown_action_
- extern void controller_entry_settings_read_print_setting_unknown_action(const bool is_entry, const controller_global_t global, const controller_cache_t cache) F_attribute_visibility_internal_d;
+ extern void controller_entry_settings_read_print_setting_unknown_action(const controller_global_t global, const bool is_entry, const controller_cache_t cache) F_attribute_visibility_internal_d;
#endif // _di_controller_entry_settings_read_print_setting_unknown_action_
/**
* Print a message for when an entry setting action has an unknown value.
*
+ * @param global
+ * The global data.
* @param is_entry
* If TRUE, then this loads as an entry.
* If FALSE, then this loads as an exit.
- * @param global
- * The global data.
* @param cache
* A structure for containing and caching relevant data.
* @param total
* The location in the content actions array representing the action value.
*/
#ifndef _di_controller_entry_settings_read_print_setting_unknown_action_value_
- extern void controller_entry_settings_read_print_setting_unknown_action_value(const bool is_entry, const controller_global_t global, const controller_cache_t cache, const f_array_length_t index) F_attribute_visibility_internal_d;
+ extern void controller_entry_settings_read_print_setting_unknown_action_value(const controller_global_t global, const bool is_entry, const controller_cache_t cache, const f_array_length_t index) F_attribute_visibility_internal_d;
#endif // _di_controller_entry_settings_read_print_setting_unknown_action_value_
#ifdef __cplusplus
#endif // _di_controller_process_find_
#ifndef _di_controller_process_prepare_
- f_status_t controller_process_prepare(const bool is_normal, const uint8_t action, const f_string_static_t alias, const controller_global_t global, f_array_length_t *id) {
+ f_status_t controller_process_prepare(const controller_global_t global, const bool is_normal, const uint8_t action, const f_string_static_t alias, f_array_length_t *id) {
f_status_t status = F_none;
#endif // _di_controller_process_prepare_
#ifndef _di_controller_process_prepare_process_type_
- f_status_t controller_process_prepare_process_type(const uint8_t type, const uint8_t action, const f_string_static_t alias, const controller_global_t global, f_array_length_t *id) {
+ f_status_t controller_process_prepare_process_type(const controller_global_t global, const uint8_t type, const uint8_t action, const f_string_static_t alias, f_array_length_t *id) {
- return controller_process_prepare(type != controller_process_type_exit_e, action, alias, global, id);
+ return controller_process_prepare(global, type != controller_process_type_exit_e, action, alias, id);
}
#endif // _di_controller_process_prepare_process_type_
#ifndef _di_controller_process_wait_
- f_status_t controller_process_wait(const controller_global_t global, controller_process_t *process) {
+ f_status_t controller_process_wait(const controller_global_t global, controller_process_t * const process) {
if (!controller_thread_is_enabled_process(process, global.thread)) {
return F_status_set_error(F_interrupt);
*
* This requires that a global.thread->lock.process lock be set on process->lock before being called.
*
+ * @param global
+ * The global data.
* @param is_normal
* If TRUE, then process as if this operates during a normal operation (entry and control).
* If FALSE, then process as if this operates during a an exit operation.
* The Rule Action to use.
* @param alias
* The Rule alias to use.
- * @param global
- * The global data.
* @param id
* (optional) The process ID when found or created.
* Set to NULL to not use.
* @see controller_lock_write()
*/
#ifndef _di_controller_process_prepare_
- extern f_status_t controller_process_prepare(const bool is_normal, const uint8_t action, const f_string_static_t alias, const controller_global_t global, f_array_length_t *id) F_attribute_visibility_internal_d;
+ extern f_status_t controller_process_prepare(const controller_global_t global, const bool is_normal, const uint8_t action, const f_string_static_t alias, f_array_length_t *id) F_attribute_visibility_internal_d;
#endif // _di_controller_process_prepare_
/**
*
* This requires that a global.thread->lock.process lock be set on process->lock before being called.
*
+ * @param global
+ * The global data.
* @param type
* The process type to use when checking if thread is enabled.
* @param action
* The Rule Action to use.
* @param alias
* The Rule alias to use.
- * @param global
- * The global data.
* @param id
* (optional) The process ID when found or created.
* Set to NULL to not use.
* @see controller_process_prepare()
*/
#ifndef _di_controller_process_prepare_process_type_
- extern f_status_t controller_process_prepare_process_type(const uint8_t type, const uint8_t action, const f_string_static_t alias, const controller_global_t global, f_array_length_t *id) F_attribute_visibility_internal_d;
+ extern f_status_t controller_process_prepare_process_type(const controller_global_t global, const uint8_t type, const uint8_t action, const f_string_static_t alias, f_array_length_t *id) F_attribute_visibility_internal_d;
#endif // _di_controller_process_prepare_process_type_
/**
* @see f_thread_condition_wait_timed()
*/
#ifndef _di_controller_process_wait_
- extern f_status_t controller_process_wait(const controller_global_t global, controller_process_t *process) F_attribute_visibility_internal_d;
+ extern f_status_t controller_process_wait(const controller_global_t global, controller_process_t * const process) F_attribute_visibility_internal_d;
#endif // _di_controller_process_wait_
#ifdef __cplusplus
#endif // _di_controller_rule_action_type_execute_name_
#ifndef _di_controller_rule_action_read_
- f_status_t controller_rule_action_read(const bool is_normal, const controller_global_t global, const uint8_t type, const uint8_t method, controller_cache_t *cache, controller_rule_item_t *item, controller_rule_actions_t *actions, f_string_range_t *range) {
+ f_status_t controller_rule_action_read(const controller_global_t global, const bool is_normal, const uint8_t type, const uint8_t method, controller_cache_t * const cache, controller_rule_item_t *item, controller_rule_actions_t *actions, f_string_range_t *range) {
f_status_t status = F_none;
if (F_status_is_error(status)) {
controller_print_error(global.main->error, F_status_set_fine(status), "controller_rule_actions_increase_by", F_true, global.thread);
+
break;
}
#endif // _di_controller_rule_action_read_
#ifndef _di_controller_rule_action_read_rerun_number_
- f_status_t controller_rule_action_read_rerun_number(const controller_global_t global, const f_string_t name, controller_cache_t *cache, f_array_length_t *index, f_number_unsigned_t *number) {
+ f_status_t controller_rule_action_read_rerun_number(const controller_global_t global, const f_string_t name, controller_cache_t * const cache, f_array_length_t *index, f_number_unsigned_t *number) {
f_status_t status = F_none;
f_number_unsigned_t parsed = 0;
}
*number = parsed;
+
return F_none;
}
#endif // _di_controller_rule_action_read_rerun_number_
f_status_t status = F_none;
- // delete the third party structures.
- macro_f_control_group_t_delete_simple(destination->control_group)
+ // Delete the third party structures.
+ macro_f_control_group_t_delete_simple(destination->cgroup)
f_capability_delete(&destination->capability);
for (f_array_length_t i = 0; i < controller_rule_action_type__enum_size_e; ++i) {
if (F_status_is_error(status)) return status;
}
- status = f_control_group_copy(source.control_group, &destination->control_group);
+ status = f_control_group_copy(source.cgroup, &destination->cgroup);
if (F_status_is_error(status)) return status;
if (source.groups.used) {
#endif // _di_controller_rule_copy_
#ifndef _di_controller_rule_execute_
- f_status_t controller_rule_execute(const uint8_t action, const uint8_t options, const controller_global_t global, controller_process_t *process) {
+ f_status_t controller_rule_execute(const controller_global_t global, const uint8_t action, const uint8_t options, controller_process_t * const process) {
f_status_t status = F_none;
f_status_t success = F_false;
f_array_length_t j = 0;
f_array_length_t k = 0;
- // child processes should receive all signals and handle the signals as they see fit.
+ // Child processes should receive all signals and handle the signals as they see fit.
f_signal_how_t signals = f_signal_how_t_initialize;
f_signal_set_empty(&signals.block);
f_signal_set_fill(&signals.block_not);
execute_set.as.capability = process->rule.capability;
}
- if (process->rule.has & controller_rule_has_control_group_d) {
- execute_set.as.control_group = &process->rule.control_group;
+ if (process->rule.has & controller_rule_has_cgroup_d) {
+ execute_set.as.control_group = &process->rule.cgroup;
- // make sure all required cgroup directories exist.
+ // Make sure all required cgroup directories exist.
if (controller_rule_status_is_available(action, process->rule)) {
- status = fll_control_group_prepare(process->rule.control_group);
+ status = fll_control_group_prepare(process->rule.cgroup);
if (F_status_is_error(status)) {
- controller_print_error_file(global.main->error, F_status_set_fine(status), "fll_control_group_prepare", F_true, process->rule.control_group.path.string, "prepare control groups for", fll_error_file_type_directory_e, global.thread);
+ controller_print_error_file(global.main->error, F_status_set_fine(status), "fll_control_group_prepare", F_true, process->rule.cgroup.path.string, "prepare control groups for", fll_error_file_type_directory_e, global.thread);
return status;
}
macro_f_string_maps_t_delete_simple(environment);
- // lock failed, attempt to re-establish lock before returning.
+ // Lock failed, attempt to re-establish lock before returning.
if (F_status_set_fine(status) == F_lock) {
status = controller_lock_read(process, global.thread, &process->lock);
#endif // _di_controller_rule_execute_
#ifndef _di_controller_rule_execute_foreground_
- f_status_t controller_rule_execute_foreground(const uint8_t type, const f_string_t program, const f_string_statics_t arguments, const uint8_t options, controller_execute_set_t * const execute_set, controller_process_t *process) {
+ f_status_t controller_rule_execute_foreground(const uint8_t type, const f_string_t program, const f_string_statics_t arguments, const uint8_t options, controller_execute_set_t * const execute_set, controller_process_t * const process) {
f_status_t status = F_none;
f_status_t status_lock = F_none;
process->result = result.status;
- // remove the pid now that waidpid() has returned.
+ // Remove the pid now that waidpid() has returned.
*child = 0;
f_thread_unlock(&process->lock);
#endif // _di_controller_rule_execute_foreground_
#ifndef _di_controller_rule_execute_pid_with_
- f_status_t controller_rule_execute_pid_with(const f_string_dynamic_t pid_file, const uint8_t type, const f_string_t program, const f_string_statics_t arguments, const uint8_t options, const uint8_t with, controller_execute_set_t * const execute_set, controller_process_t *process) {
+ f_status_t controller_rule_execute_pid_with(const f_string_dynamic_t pid_file, const uint8_t type, const f_string_t program, const f_string_statics_t arguments, const uint8_t options, const uint8_t with, controller_execute_set_t * const execute_set, controller_process_t * const process) {
f_status_t status = F_none;
f_status_t status_lock = F_none;
#endif // _di_controller_rule_execute_pid_with_
#ifndef _di_controller_rule_execute_rerun_
- int8_t controller_rule_execute_rerun(const uint8_t action, controller_process_t *process, controller_rule_item_t *item) {
+ int8_t controller_rule_execute_rerun(const uint8_t action, controller_process_t * const process, controller_rule_item_t *item) {
const int result = WIFEXITED(process->result) ? WEXITSTATUS(process->result) : 0;
#endif // _di_controller_rule_status_is_error_
#ifndef _di_controller_rule_item_read_
- f_status_t controller_rule_item_read(const bool is_normal, const controller_global_t global, controller_cache_t *cache, controller_rule_item_t *item) {
+ f_status_t controller_rule_item_read(const controller_global_t global, const bool is_normal, controller_cache_t * const cache, controller_rule_item_t *item) {
f_status_t status = F_none;
controller_state_interrupt_t custom = macro_controller_state_interrupt_t_initialize(is_normal, global.thread);
break;
}
- status = controller_rule_action_read(is_normal, global, type, method, cache, item, &item->actions, &range);
+ status = controller_rule_action_read(global, is_normal, type, method, cache, item, &item->actions, &range);
if (F_status_is_error(status)) break;
} // for
#endif // _di_controller_rule_setting_limit_type_name_
#ifndef _di_controller_rule_process_
- f_status_t controller_rule_process(const controller_global_t global, controller_process_t *process) {
+ f_status_t controller_rule_process(const controller_global_t global, controller_process_t * const process) {
switch (process->action) {
case controller_rule_action_type_freeze_e:
}
if ((process->options & controller_process_option_simulate_d) && (process->options & controller_process_option_validate_d)) {
- controller_rule_validate(process->rule, process->action, process->options, global, &process->cache);
+ controller_rule_validate(global, process->rule, process->action, process->options, &process->cache);
}
f_array_length_t i = 0;
controller_lock_print_error_critical(global.main->error, F_status_set_fine(status_lock), F_true, global.thread);
}
else {
- status = controller_process_prepare_process_type(process->type, process->action, dynamics[i]->array[j], global, &id_dependency);
+ status = controller_process_prepare_process_type(global, process->type, process->action, dynamics[i]->array[j], &id_dependency);
if (F_status_is_error(status)) {
if (F_status_set_fine(status) == F_lock) {
return F_status_set_error(F_interrupt);
}
}
- else {
-
- }
if (global.main->error.verbosity != f_console_verbosity_quiet_e) {
controller_lock_print(global.main->error.to, global.thread);
// the dependency may have write locks, which needs to be avoided, so copy the alias from the rule.
char alias_other_buffer[global.setting->rules.array[id_rule].alias.used + 1];
- memcpy(alias_other_buffer, global.setting->rules.array[id_rule].alias.string, sizeof(char) * global.setting->rules.array[id_rule].alias.used);
+ memcpy(alias_other_buffer, global.setting->rules.array[id_rule].alias.string, global.setting->rules.array[id_rule].alias.used);
alias_other_buffer[global.setting->rules.array[id_rule].alias.used] = 0;
const f_string_static_t alias_other = macro_f_string_static_t_initialize(alias_other_buffer, global.setting->rules.array[id_rule].alias.used);
}
// Synchronously execute dependency.
- status = controller_rule_process_begin(0, alias_other, process->action, options_process, process->type, process->stack, global, dependency->cache);
+ status = controller_rule_process_begin(global, 0, alias_other, process->action, options_process, process->type, process->stack, dependency->cache);
if (status == F_child || F_status_set_fine(status) == F_interrupt) {
f_thread_unlock(&dependency->active);
}
if ((process->options & controller_process_option_wait_d) && F_status_is_error_not(status) && (process->options & controller_process_option_validate_d)) {
- status_lock = controller_rule_wait_all_process_type(process->type, global, F_false, process);
+ status_lock = controller_rule_wait_all_process_type(global, process->type, F_false, process);
if (F_status_set_fine(status_lock) == F_interrupt) {
return status_lock;
}
if (F_status_is_error_not(status)) {
- status = controller_rule_execute(process->action, process->options, global, process);
+ status = controller_rule_execute(global, process->action, process->options, process);
if (status == F_child || F_status_set_fine(status) == F_interrupt || F_status_set_fine(status) == F_lock) {
return status;
controller_rule_action_t *rule_action = 0;
// @todo implement a "version" counter and detect if the rule version is different before attempting update.
- // copy all rule item action statuses from the rule process to the rule.
+ // Copy all rule item action statuses from the rule process to the rule.
for (i = 0; i < rule->items.used; ++i) {
rule_item = &rule->items.array[i];
#endif // _di_controller_rule_process_
#ifndef _di_controller_rule_process_begin_
- f_status_t controller_rule_process_begin(const uint8_t options_force, const f_string_static_t alias_rule, const uint8_t action, const uint8_t options, const uint8_t type, const f_array_lengths_t stack, const controller_global_t global, const controller_cache_t cache) {
+ f_status_t controller_rule_process_begin(const controller_global_t global, const uint8_t options_force, const f_string_static_t alias_rule, const uint8_t action, const uint8_t options, const uint8_t type, const f_array_lengths_t stack, const controller_cache_t cache) {
if (!controller_thread_is_enabled_process_type(type, global.thread)) {
return F_status_set_error(F_interrupt);
{
f_array_length_t at = 0;
- status = controller_process_prepare(type != controller_process_type_exit_e, action, alias_rule, global, &at);
+ status = controller_process_prepare(global, type != controller_process_type_exit_e, action, alias_rule, &at);
if (F_status_is_error(status)) {
f_thread_unlock(&global.thread->lock.process);
#endif // _di_controller_rule_process_begin_
#ifndef _di_controller_rule_process_do_
- f_status_t controller_rule_process_do(const uint8_t options_force, controller_process_t *process) {
+ f_status_t controller_rule_process_do(const uint8_t options_force, controller_process_t * const process) {
f_status_t status_lock = F_none;
controller_global_t global = macro_controller_global_t_initialize((controller_main_t *) process->main_data, (controller_setting_t *) process->main_setting, (controller_thread_t *) process->main_thread);
- // the process and active locks shall be held for the duration of this processing (aside from switching between read to/from write).
+ // The process and active locks shall be held for the duration of this processing (aside from switching between read to/from write).
if (options_force & controller_process_option_asynchronous_d) {
status_lock = controller_lock_read_process(process, global.thread, &process->active);
#endif // _di_controller_rule_process_do_
#ifndef _di_controller_rule_read_
- f_status_t controller_rule_read(const bool is_normal, const f_string_static_t alias, controller_global_t global, controller_cache_t *cache, controller_entry_t *entry, controller_rule_t *rule) {
+ f_status_t controller_rule_read(const controller_global_t global, const bool is_normal, const f_string_static_t alias, controller_cache_t * const cache, controller_entry_t * const entry, controller_rule_t * const rule) {
f_status_t status = F_none;
rule->capability = 0;
}
- for (f_array_length_t i = 0; i < rule->control_group.groups.size; ++i) {
- rule->control_group.groups.array[i].used = 0;
+ for (f_array_length_t i = 0; i < rule->cgroup.groups.size; ++i) {
+ rule->cgroup.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->cgroup.as_new = F_false;
+ rule->cgroup.path.used = 0;
+ rule->cgroup.groups.used = 0;
- macro_f_control_group_t_clear(rule->control_group);
+ macro_f_control_group_t_clear(rule->cgroup);
rule->groups.used = 0;
rule->limits.used = 0;
controller_print_error(global.main->error, F_status_set_fine(status), "f_string_dynamic_append_nulless", F_true, global.thread);
}
else {
-
status = f_string_dynamic_terminate_after(&rule->alias);
if (F_status_is_error(status)) {
controller_print_error(global.main->error, F_status_set_fine(status), "f_string_dynamic_terminate_after", F_true, global.thread);
}
else {
- status = controller_file_load(F_true, controller_rules_s, rule->alias, controller_rule_s, controller_rules_s_length, controller_rule_s_length, global, cache);
+ status = controller_file_load(global, F_true, controller_rules_s, rule->alias, controller_rule_s, controller_rules_s_length, controller_rule_s_length, cache);
}
}
if (rule->items.array[rule->items.used].type) {
- // initialize the item with settings.
+ // Initialize the item with settings.
rule->items.array[rule->items.used].with = 0;
if (entry->session == controller_entry_session_new_e) {
rule->items.array[rule->items.used].with |= controller_with_session_same_d;
}
- status = controller_rule_item_read(is_normal, global, cache, &rule->items.array[rule->items.used]);
+ status = controller_rule_item_read(global, is_normal, cache, &rule->items.array[rule->items.used]);
if (F_status_is_error(status)) break;
++rule->items.used;
else {
for_item = F_false;
- status = controller_rule_setting_read(is_normal, global, *global.setting, cache, rule);
+ status = controller_rule_setting_read(global, is_normal, *global.setting, cache, rule);
if (F_status_is_error(status)) {
if (F_status_set_fine(status) == F_memory_not) {
#endif // _di_controller_rule_read_
#ifndef _di_controller_rule_setting_read_
- f_status_t controller_rule_setting_read(const bool is_normal, const controller_global_t global, const controller_setting_t setting, controller_cache_t *cache, controller_rule_t *rule) {
+ f_status_t controller_rule_setting_read(const controller_global_t global, const bool is_normal, const controller_setting_t setting, controller_cache_t * const cache, controller_rule_t * const rule) {
f_status_t status = F_none;
f_status_t status_return = F_none;
uint8_t action = 0;
bool empty_disallow = F_true;
- // save the current name item and line number to restore on return.
+ // Save the current name item and line number to restore on return.
const f_array_length_t line_item = cache->action.line_item;
const f_array_length_t length_name_item = cache->action.name_item.used;
for (; i < cache->content_actions.used; ++i, type = 0) {
- // name_action is used to store all setting values for a single setting.
+ // The name_action is used to store all setting values for a single setting.
cache->action.name_action.used = 0;
- // name_item is used to store the setting name.
+ // The name_item is used to store the setting name.
cache->action.name_item.used = 0;
status = f_string_dynamic_partial_append_nulless(cache->buffer_item, cache->object_actions.array[i], &cache->action.name_item);
status_return = status;
}
- // get the current line number within the settings item.
+ // Get the current line number within the settings item.
cache->action.line_item = line_item;
f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
else if (fl_string_dynamic_compare_string(controller_capability_s, cache->action.name_item, controller_capability_s_length) == F_equal_to) {
type = controller_rule_setting_type_capability_e;
}
- else if (fl_string_dynamic_compare_string(controller_control_group_s, cache->action.name_item, controller_control_group_s_length) == F_equal_to) {
- type = controller_rule_setting_type_control_group_e;
+ else if (fl_string_dynamic_compare_string(controller_cgroup_s, cache->action.name_item, controller_cgroup_s_length) == F_equal_to) {
+ type = controller_rule_setting_type_cgroup_e;
}
else if (fl_string_dynamic_compare_string(controller_define_s, cache->action.name_item, controller_define_s_length) == F_equal_to) {
type = controller_rule_setting_type_define_e;
else {
if (global.main->warning.verbosity == f_console_verbosity_debug_e) {
- // get the current line number within the settings item.
+ // Get the current line number within the settings item.
cache->action.line_item = line_item;
f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
if (F_status_is_error(status)) {
- // get the current line number within the settings item.
+ // Get the current line number within the settings item.
cache->action.line_item = line_item;
f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
if (empty_disallow) {
if (global.main->warning.verbosity == f_console_verbosity_debug_e) {
- // get the current line number within the settings item.
+ // Get the current line number within the settings item.
cache->action.line_item = line_item;
f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
if (status == F_data_not || status == F_number || status == F_number_overflow || status == F_number_underflow || status == F_number_negative || status == F_number_decimal) {
if (status == F_number_underflow) {
- controller_rule_setting_read_print_error_with_range(global.main->error, "has an unsupported number", cache->content_actions.array[i].array[j], ", the number is too small for this system", i, line_item, global.thread, cache);
+ controller_rule_setting_read_print_error_with_range(global.main->error, " has an unsupported number", cache->content_actions.array[i].array[j], ", the number is too small for this system", i, line_item, global.thread, cache);
}
else if (status == F_number_overflow || status == F_number_positive) {
- controller_rule_setting_read_print_error_with_range(global.main->error, "has an unsupported number", cache->content_actions.array[i].array[j], ", the number is too large for this system", i, line_item, global.thread, cache);
+ controller_rule_setting_read_print_error_with_range(global.main->error, " has an unsupported number", cache->content_actions.array[i].array[j], ", the number is too large for this system", i, line_item, global.thread, cache);
}
else {
- controller_rule_setting_read_print_error_with_range(global.main->error, "has an invalid number", cache->content_actions.array[i].array[j], ", only whole numbers are allowed for an affinity value", i, line_item, global.thread, cache);
+ controller_rule_setting_read_print_error_with_range(global.main->error, " has an invalid number", cache->content_actions.array[i].array[j], ", only whole numbers are allowed for an affinity value", i, line_item, global.thread, cache);
}
status = F_status_set_error(F_valid_not);
}
if (type == controller_rule_setting_type_define_e || type == controller_rule_setting_type_parameter_e) {
-
if (cache->content_actions.array[i].used != 2) {
controller_rule_setting_read_print_error(global.main->error, "requires exactly two Content", i, line_item, global.thread, cache);
status_return = status;
}
- // get the current line number within the settings item.
+ // Get the current line number within the settings item.
cache->action.line_item = line_item;
f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
status_return = status;
}
- // get the current line number within the settings item.
+ // Get the current line number within the settings item.
cache->action.line_item = line_item;
f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
status_return = status;
}
- // get the current line number within the settings item.
+ // Get the current line number within the settings item.
cache->action.line_item = line_item;
f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
continue;
}
- if (type == controller_rule_setting_type_control_group_e) {
- if (cache->content_actions.array[i].used < 2 || rule->has & controller_rule_has_control_group_d) {
+ if (type == controller_rule_setting_type_cgroup_e) {
+ if (cache->content_actions.array[i].used < 2 || rule->has & controller_rule_has_cgroup_d) {
controller_rule_setting_read_print_error(global.main->error, "requires two or more Content", i, line_item, global.thread, cache);
if (F_status_is_error_not(status_return)) {
}
if (fl_string_dynamic_partial_compare_string(controller_existing_s, cache->buffer_item, controller_existing_s_length, cache->content_actions.array[i].array[0]) == F_equal_to) {
- rule->control_group.as_new = F_false;
+ rule->cgroup.as_new = F_false;
}
else if (fl_string_dynamic_partial_compare_string(controller_new_s, cache->buffer_item, controller_new_s_length, cache->content_actions.array[i].array[0]) == F_equal_to) {
- rule->control_group.as_new = F_true;
+ rule->cgroup.as_new = F_true;
}
else {
- controller_rule_setting_read_print_error_with_range(global.main->error, "has an unknown option", cache->content_actions.array[i].array[0], "", i, line_item, global.thread, cache);
+ controller_rule_setting_read_print_error_with_range(global.main->error, " has an unknown option", cache->content_actions.array[i].array[0], "", i, line_item, global.thread, cache);
if (F_status_is_error_not(status_return)) {
status_return = F_status_set_error(F_valid_not);
continue;
}
- rule->control_group.path.used = 0;
+ rule->cgroup.path.used = 0;
- status = f_string_dynamic_append(global.setting->path_control, &rule->control_group.path);
+ status = f_string_dynamic_append(global.setting->path_cgroup, &rule->cgroup.path);
if (F_status_is_error(status)) {
controller_rule_print_error(global.main->error, cache->action, F_status_set_fine(status), "f_string_dynamic_append", F_true, F_false, global.thread);
}
else {
- rule->control_group.groups.used = 0;
+ rule->cgroup.groups.used = 0;
for (j = 1; j < cache->content_actions.array[i].used; ++j) {
- status = f_string_dynamics_increase(controller_common_allocation_small_d, &rule->control_group.groups);
+ status = f_string_dynamics_increase(controller_common_allocation_small_d, &rule->cgroup.groups);
if (F_status_is_error(status)) {
controller_rule_print_error(global.main->error, cache->action, F_status_set_fine(status), "f_string_dynamics_increase", F_true, F_false, global.thread);
break;
}
- rule->control_group.groups.array[rule->control_group.groups.used].used = 0;
+ rule->cgroup.groups.array[rule->cgroup.groups.used].used = 0;
- status = f_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]);
+ status = f_string_dynamic_partial_append_nulless(cache->buffer_item, cache->content_actions.array[i].array[j], &rule->cgroup.groups.array[rule->cgroup.groups.used]);
if (F_status_is_error(status)) {
controller_rule_print_error(global.main->error, cache->action, F_status_set_fine(status), "f_string_dynamic_partial_append_nulless", F_true, F_false, global.thread);
break;
}
- ++rule->control_group.groups.used;
+ ++rule->cgroup.groups.used;
} // for
}
break;
}
- rule->control_group.path.used = 0;
+ rule->cgroup.path.used = 0;
if (F_status_is_error_not(status_return)) {
status_return = status;
continue;
}
- rule->has |= controller_rule_has_control_group_d;
+ rule->has |= controller_rule_has_cgroup_d;
- controller_rule_setting_read_print_values(global, controller_control_group_s, i, cache);
+ controller_rule_setting_read_print_values(global, controller_cgroup_s, i, cache);
continue;
}
else {
if (global.main->error.verbosity == f_console_verbosity_debug_e) {
- // get the current line number within the settings item.
+ // Get the current line number within the settings item.
cache->action.line_item = line_item;
f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
if (status == F_data_not || status == F_number || status == F_number_overflow || status == F_number_underflow || status == F_number_negative || status == F_number_positive || status == F_number_decimal) {
if (status == F_number_underflow) {
- controller_rule_setting_read_print_error_with_range(global.main->error, "has an unsupported number", cache->content_actions.array[i].array[j], ", the number is too small for this system", i, line_item, global.thread, cache);
+ controller_rule_setting_read_print_error_with_range(global.main->error, " has an unsupported number", cache->content_actions.array[i].array[j], ", the number is too small for this system", i, line_item, global.thread, cache);
}
else if (status == F_number_overflow) {
- controller_rule_setting_read_print_error_with_range(global.main->error, "has an unsupported number", cache->content_actions.array[i].array[j], ", the number is too large for this system", i, line_item, global.thread, cache);
+ controller_rule_setting_read_print_error_with_range(global.main->error, " has an unsupported number", cache->content_actions.array[i].array[j], ", the number is too large for this system", i, line_item, global.thread, cache);
}
else {
- controller_rule_setting_read_print_error_with_range(global.main->error, "has an unsupported number", cache->content_actions.array[i].array[j], ", only whole numbers are allowed for a resource limit value", i, line_item, global.thread, cache);
+ controller_rule_setting_read_print_error_with_range(global.main->error, " has an unsupported number", cache->content_actions.array[i].array[j], ", only whole numbers are allowed for a resource limit value", i, line_item, global.thread, cache);
}
status = F_status_set_error(F_valid_not);
rule->scheduler.priority = 49;
}
else {
- controller_rule_setting_read_print_error_with_range(global.main->error, "has an unknown scheduler", cache->content_actions.array[i].array[0], "", i, line_item, global.thread, cache);
+ controller_rule_setting_read_print_error_with_range(global.main->error, " has an unknown scheduler", cache->content_actions.array[i].array[0], "", i, line_item, global.thread, cache);
if (F_status_is_error_not(status_return)) {
status_return = F_status_set_error(F_valid_not);
else {
if (global.main->error.verbosity != f_console_verbosity_quiet_e) {
- // get the current line number within the settings item.
+ // Get the current line number within the settings item.
cache->action.line_item = line_item;
f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
status = F_status_set_fine(status);
if (status == F_number_overflow) {
- controller_rule_setting_read_print_error_with_range(global.main->error, "has an unsupported number", cache->content_actions.array[i].array[1], ", the number is too large for this system", i, line_item, global.thread, cache);
+ controller_rule_setting_read_print_error_with_range(global.main->error, " has an unsupported number", cache->content_actions.array[i].array[1], ", the number is too large for this system", i, line_item, global.thread, cache);
}
else if (status == F_data_not || status == F_number || status == F_number_underflow || status == F_number_negative || status == F_number_positive || status == F_number_decimal) {
- controller_rule_setting_read_print_error_with_range(global.main->error, "has an invalid number", cache->content_actions.array[i].array[1], ", only positive whole numbers are allowed", i, line_item, global.thread, cache);
+ controller_rule_setting_read_print_error_with_range(global.main->error, " has an invalid number", cache->content_actions.array[i].array[1], ", only positive whole numbers are allowed", i, line_item, global.thread, cache);
}
else {
- // get the current line number within the settings item.
+ // Get the current line number within the settings item.
cache->action.line_item = line_item;
f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
if (F_status_is_error(status)) {
- // get the current line number within the settings item.
+ // Get the current line number within the settings item.
cache->action.line_item = line_item;
f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
if (F_status_is_error(status)) {
- // get the current line number within the settings item.
+ // Get the current line number within the settings item.
cache->action.line_item = line_item;
f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
if (F_status_is_error(status) && F_status_set_fine(status) != F_supported_not) {
if (F_status_set_fine(status) == F_memory_not) {
- // get the current line number within the settings item.
+ // Get the current line number within the settings item.
cache->action.line_item = line_item;
f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
if (number < -20 || number > 19 || status == F_data_not || status == F_number || status == F_number_overflow || status == F_number_underflow || status == F_number_decimal) {
if (global.main->error.verbosity != f_console_verbosity_quiet_e) {
- // get the current line number within the settings item.
+ // Get the current line number within the settings item.
cache->action.line_item = line_item;
f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
if (F_status_is_error(status)) {
- // get the current line number within the settings item.
+ // Get the current line number within the settings item.
cache->action.line_item = line_item;
f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
status = F_status_set_fine(status);
if (status == F_exist_not) {
- controller_rule_setting_read_print_error_with_range(global.main->error, "has an invalid user", cache->content_actions.array[i].array[0], ", because no user was found by that name", i, line_item, global.thread, cache);
+ controller_rule_setting_read_print_error_with_range(global.main->error, " has an invalid user", cache->content_actions.array[i].array[0], ", because no user was found by that name", i, line_item, global.thread, cache);
}
else if (status == F_number_too_large) {
- controller_rule_setting_read_print_error_with_range(global.main->error, "has an invalid user", cache->content_actions.array[i].array[0], ", because the given ID is too large", i, line_item, global.thread, cache);
+ controller_rule_setting_read_print_error_with_range(global.main->error, " has an invalid user", cache->content_actions.array[i].array[0], ", because the given ID is too large", i, line_item, global.thread, cache);
}
else if (status == F_number) {
- controller_rule_setting_read_print_error_with_range(global.main->error, "has an invalid user", cache->content_actions.array[i].array[0], ", because the given ID is not a valid supported number", i, line_item, global.thread, cache);
+ controller_rule_setting_read_print_error_with_range(global.main->error, " has an invalid user", cache->content_actions.array[i].array[0], ", because the given ID is not a valid supported number", i, line_item, global.thread, cache);
}
else {
- // get the current line number within the settings item.
+ // Get the current line number within the settings item.
cache->action.line_item = line_item;
f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
cache->action.line_action = ++cache->action.line_item;
- controller_rule_print_error(global.main->error, cache->action, status, "f_account_id_user_by_name", F_true, F_false, global.thread);
+ controller_rule_print_error(global.main->error, cache->action, status, "controller_get_id_user", F_true, F_false, global.thread);
controller_rule_item_print_error(global.main->error, cache->action, F_false, F_status_set_fine(status), global.thread);
}
status_return = status;
}
- // get the current line number within the settings item.
+ // Get the current line number within the settings item.
cache->action.line_item = line_item;
f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
status = F_status_set_fine(status);
if (status == F_exist_not) {
- controller_rule_setting_read_print_error_with_range(global.main->error, "has an invalid group", cache->content_actions.array[i].array[j], ", because no group was found by that name", i, line_item, global.thread, cache);
+ controller_rule_setting_read_print_error_with_range(global.main->error, " has an invalid group", cache->content_actions.array[i].array[j], ", because no group was found by that name", i, line_item, global.thread, cache);
}
else if (status == F_number_too_large) {
- controller_rule_setting_read_print_error_with_range(global.main->error, "has an invalid group", cache->content_actions.array[i].array[j], ", because the given ID is too large", i, line_item, global.thread, cache);
+ controller_rule_setting_read_print_error_with_range(global.main->error, " has an invalid group", cache->content_actions.array[i].array[j], ", because the given ID is too large", i, line_item, global.thread, cache);
}
else if (status == F_number) {
- controller_rule_setting_read_print_error_with_range(global.main->error, "has an invalid group", cache->content_actions.array[i].array[j], ", because the given ID is not a valid supported number", i, line_item, global.thread, cache);
+ controller_rule_setting_read_print_error_with_range(global.main->error, " has an invalid group", cache->content_actions.array[i].array[j], ", because the given ID is not a valid supported number", i, line_item, global.thread, cache);
}
else {
status_return = status;
}
- // get the current line number within the settings item.
+ // Get the current line number within the settings item.
cache->action.line_item = line_item;
f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
status_return = status;
}
- // get the current line number within the settings item.
+ // Get the current line number within the settings item.
cache->action.line_item = line_item;
f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
if (status == F_false || F_status_set_fine(status) == F_complete_not_utf) {
- // get the current line number within the settings item.
+ // Get the current line number within the settings item.
cache->action.line_item = line_item;
f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
}
else {
- // this function should only return F_complete_not_utf on error.
+ // This function should only return F_complete_not_utf on error.
controller_rule_print_error(global.main->error, cache->action, F_complete_not_utf, "controller_validate_environment_name", F_true, F_false, global.thread);
if (F_status_is_error_not(status_return)) {
else {
if (global.main->error.verbosity != f_console_verbosity_quiet_e) {
- // get the current line number within the settings item.
+ // Get the current line number within the settings item.
cache->action.line_item = line_item;
f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
else {
if (global.main->error.verbosity != f_console_verbosity_quiet_e) {
- // get the current line number within the settings item.
+ // Get the current line number within the settings item.
cache->action.line_item = line_item;
f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
status_return = status;
}
- // get the current line number within the settings item.
+ // Get the current line number within the settings item.
cache->action.line_item = line_item;
f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
status_return = status;
}
- // get the current line number within the settings item.
+ // Get the current line number within the settings item.
cache->action.line_item = line_item;
f_fss_count_lines(cache->buffer_item, cache->object_actions.array[i].start, &cache->action.line_item);
}
} // for
- // resore the current name item and line number, which there should already be enough allocated space for.
+ // Restore the current name item and line number, which there should already be enough allocated space for.
memcpy(cache->action.name_item.string, name_item, length_name_item);
cache->action.name_item.string[length_name_item] = 0;
#endif // _di_controller_rule_setting_read_
#ifndef _di_controller_rule_validate_
- void controller_rule_validate(const controller_rule_t rule, const uint8_t action, const uint8_t options, const controller_global_t global, controller_cache_t *cache) {
+ void controller_rule_validate(const controller_global_t global, const controller_rule_t rule, const uint8_t action, const uint8_t options, controller_cache_t * const cache) {
const controller_main_t *main = global.main;
}
// control group.
- fl_print_format(" %[%s%]", main->output.to.stream, main->context.set.important, controller_control_group_s, main->context.set.important);
+ fl_print_format(" %[%s%]", main->output.to.stream, main->context.set.important, controller_cgroup_s, main->context.set.important);
- if (rule.has & controller_rule_has_control_group_d) {
- fl_print_format(" %s", main->output.to.stream, rule.control_group.as_new ? controller_new_s : controller_existing_s);
+ if (rule.has & controller_rule_has_cgroup_d) {
+ fl_print_format(" %s", main->output.to.stream, rule.cgroup.as_new ? controller_new_s : controller_existing_s);
- for (i = 0; i < rule.control_group.groups.used; ++i) {
+ for (i = 0; i < rule.cgroup.groups.used; ++i) {
- if (rule.control_group.groups.array[i].used) {
- fl_print_format(" %Q", main->output.to.stream, rule.control_group.groups.array[i]);
+ if (rule.cgroup.groups.array[i].used) {
+ fl_print_format(" %Q", main->output.to.stream, rule.cgroup.groups.array[i]);
}
} // for
}
#endif // _di_controller_rule_validate_
#ifndef _di_controller_rule_wait_all_
- f_status_t controller_rule_wait_all(const bool is_normal, const controller_global_t global, const bool required, controller_process_t *caller) {
+ f_status_t controller_rule_wait_all(const controller_global_t global, const bool is_normal, const bool required, controller_process_t * const caller) {
f_status_t status_lock = F_none;
#endif // _di_controller_rule_wait_all_
#ifndef _di_controller_rule_wait_all_process_type_
- f_status_t controller_rule_wait_all_process_type(const uint8_t type, const controller_global_t global, const bool required, controller_process_t *caller) {
+ f_status_t controller_rule_wait_all_process_type(const controller_global_t global, const uint8_t type, const bool required, controller_process_t * const caller) {
- return controller_rule_wait_all(type != controller_process_type_exit_e, global, required, caller);
+ return controller_rule_wait_all(global, type != controller_process_type_exit_e, required, caller);
}
#endif // _di_controller_rule_wait_all_process_type_
*
* This will automatically increase the size of the actions array as needed.
*
+ * @param global
+ * The global data.
* @param is_normal
* If TRUE, then process as if this operates during a normal operation (entry and control).
* If FALSE, then process as if this operates during a an exit operation.
- * @param global
- * The global data.
* @param type
* The action type for this action or set of actions.
* @param method
* @see f_fss_count_lines()
*/
#ifndef _di_controller_rule_action_read_
- extern f_status_t controller_rule_action_read(const bool is_normal, const controller_global_t global, const uint8_t type, const uint8_t method, controller_cache_t *cache, controller_rule_item_t *item, controller_rule_actions_t *actions, f_string_range_t *range) F_attribute_visibility_internal_d;
+ extern f_status_t controller_rule_action_read(const controller_global_t global, const bool is_normal, const uint8_t type, const uint8_t method, controller_cache_t * const cache, controller_rule_item_t *item, controller_rule_actions_t *actions, f_string_range_t *range) F_attribute_visibility_internal_d;
#endif // _di_controller_rule_action_read_
/**
*
* This requires that a read lock be set on process->lock before being called.
*
+ * @param global
+ * The global data.
* @param action
* The action to perform based on the action type codes.
*
* @param options
* Process options to consider when executing.
* If bit controller_process_option_simulate_d, then the rule execution is in simulation mode (printing a message that the rule would be executed but does not execute the rule).
- * @param global
- * The global data.
* @param process
* The process data for processing this rule.
*
* On failure, the individual status for the rule is set to an appropriate error status.
*/
#ifndef _di_controller_rule_execute_
- extern f_status_t controller_rule_execute(const uint8_t action, const uint8_t options, const controller_global_t global, controller_process_t *process) F_attribute_visibility_internal_d;
+ extern f_status_t controller_rule_execute(const controller_global_t global, const uint8_t action, const uint8_t options, controller_process_t * const process) F_attribute_visibility_internal_d;
#endif // _di_controller_rule_execute_
/**
* @see fll_execute_program()
*/
#ifndef _di_controller_rule_execute_foreground_
- extern f_status_t controller_rule_execute_foreground(const uint8_t type, const f_string_t program, const f_string_statics_t arguments, const uint8_t options, controller_execute_set_t * const execute_set, controller_process_t *process) F_attribute_visibility_internal_d;
+ extern f_status_t controller_rule_execute_foreground(const uint8_t type, const f_string_t program, const f_string_statics_t arguments, const uint8_t options, controller_execute_set_t * const execute_set, controller_process_t * const process) F_attribute_visibility_internal_d;
#endif // _di_controller_rule_execute_foreground_
/**
* @see fll_execute_program()
*/
#ifndef _di_controller_rule_execute_pid_with_
- extern f_status_t controller_rule_execute_pid_with(const f_string_dynamic_t pid_file, const uint8_t type, const f_string_t program, const f_string_statics_t arguments, const uint8_t options, const uint8_t with, controller_execute_set_t * const execute_set, controller_process_t *process) F_attribute_visibility_internal_d;
+ extern f_status_t controller_rule_execute_pid_with(const f_string_dynamic_t pid_file, const uint8_t type, const f_string_t program, const f_string_statics_t arguments, const uint8_t options, const uint8_t with, controller_execute_set_t * const execute_set, controller_process_t * const process) F_attribute_visibility_internal_d;
#endif // _di_controller_rule_execute_pid_with_
/**
* -2 to designate exit due to signal/disabled thread.
*/
#ifndef _di_controller_rule_execute_rerun_
- extern int8_t controller_rule_execute_rerun(const uint8_t action, controller_process_t *process, controller_rule_item_t *item) F_attribute_visibility_internal_d;
+ extern int8_t controller_rule_execute_rerun(const uint8_t action, controller_process_t * const process, controller_rule_item_t *item) F_attribute_visibility_internal_d;
#endif // _di_controller_rule_execute_rerun_
/**
*
* This will perform additional FSS read functions as appropriate.
*
+ * @param global
+ * The global data.
* @param is_normal
* If TRUE, then process as if this operates during a normal operation (entry and control).
* If FALSE, then process as if this operates during a an exit operation.
- * @param global
- * The global data.
* @param cache
* A structure for containing and caching relevant data.
* @param item
* @see f_string_dynamic_terminate_after()
*/
#ifndef _di_controller_rule_item_read_
- extern f_status_t controller_rule_item_read(const bool is_normal, const controller_global_t global, controller_cache_t *cache, controller_rule_item_t *item) F_attribute_visibility_internal_d;
+ extern f_status_t controller_rule_item_read(const controller_global_t global, const bool is_normal, controller_cache_t * const cache, controller_rule_item_t *item) F_attribute_visibility_internal_d;
#endif // _di_controller_rule_item_read_
/**
* Errors (with error bit) from: controller_lock_write().
*/
#ifndef _di_controller_rule_process_
- extern f_status_t controller_rule_process(const controller_global_t global, controller_process_t *process) F_attribute_visibility_internal_d;
+ extern f_status_t controller_rule_process(const controller_global_t global, controller_process_t * const process) F_attribute_visibility_internal_d;
#endif // _di_controller_rule_process_
/**
* Synchronously or asynchronously begin processing some rule.
*
+ * @param global
+ * The global data.
* @param options_force
* Force the given process options, only supporting a subset of process options.
*
* @param stack
* A stack representing the processes already running in this rule process dependency tree.
* This is used to prevent circular dependencies.
- * @param global
- * The global data.
* @param cache
* A structure for containing and caching relevant data.
*
* @see f_thread_create()
*/
#ifndef _di_controller_rule_process_begin_
- extern f_status_t controller_rule_process_begin(const uint8_t options_force, const f_string_static_t alias_rule, const uint8_t action, const uint8_t options, const uint8_t type, const f_array_lengths_t stack, const controller_global_t global, const controller_cache_t cache) F_attribute_visibility_internal_d;
+ extern f_status_t controller_rule_process_begin(const controller_global_t global, const uint8_t options_force, const f_string_static_t alias_rule, const uint8_t action, const uint8_t options, const uint8_t type, const f_array_lengths_t stack, const controller_cache_t cache) F_attribute_visibility_internal_d;
#endif // _di_controller_rule_process_begin_
/**
* @see controller_rule_process_begin()
*/
#ifndef _di_controller_rule_process_do_
- extern f_status_t controller_rule_process_do(const uint8_t options_force, controller_process_t *process) F_attribute_visibility_internal_d;
+ extern f_status_t controller_rule_process_do(const uint8_t options_force, controller_process_t * const process) F_attribute_visibility_internal_d;
#endif // _di_controller_rule_process_do_
/**
* Read the rule file, extracting all valid items.
*
+ * @param global
+ * The global data.
* @param is_normal
* If TRUE, then process as if this operates during a normal operation (entry and control).
* If FALSE, then process as if this operates during a an exit operation.
* The string identifying the rule.
* This is constructed from the path parts to the file without the file extension and without the settings directory prefix.
* "/etc/controller/rules/example/my.rule" would have a rule id of "example/my".
- * @param global
- * The global data.
* @param cache
* A structure for containing and caching relevant data.
* @param entry
* @see fll_fss_basic_list_read().
*/
#ifndef _di_controller_rule_read_
- extern f_status_t controller_rule_read(const bool is_normal, const f_string_static_t alias, controller_global_t global, controller_cache_t *cache, controller_entry_t *entry, controller_rule_t *rule) F_attribute_visibility_internal_d;
+ extern f_status_t controller_rule_read(const controller_global_t global, const bool is_normal, const f_string_static_t alias, controller_cache_t * const cache, controller_entry_t * const entry, controller_rule_t * const rule) F_attribute_visibility_internal_d;
#endif // _di_controller_rule_read_
/**
* @see fl_conversion_string_to_number_signed()
*/
#ifndef _di_controller_rule_action_read_rerun_number_
- extern f_status_t controller_rule_action_read_rerun_number(const controller_global_t global, const f_string_t name, controller_cache_t *cache, f_array_length_t *index, f_number_unsigned_t *number) F_attribute_visibility_internal_d;
+ extern f_status_t controller_rule_action_read_rerun_number(const controller_global_t global, const f_string_t name, controller_cache_t * const cache, f_array_length_t *index, f_number_unsigned_t *number) F_attribute_visibility_internal_d;
#endif // _di_controller_rule_action_read_rerun_number_
/**
* Errors from this are not considered fatal, but the first error code encountered is returned.
* Memory failure errors are always immediately returned.
*
+ * @param global
+ * The global data.
* @param is_normal
* If TRUE, then process as if this operates during a normal operation (entry and control).
* If FALSE, then process as if this operates during a an exit operation.
- * @param global
- * The global data.
* @param setting
* The controller settings data.
* @param cache
* @see fll_path_canonical()
*/
#ifndef _di_controller_rule_setting_read_
- extern f_status_t controller_rule_setting_read(const bool is_normal, const controller_global_t global, const controller_setting_t setting, controller_cache_t *cache, controller_rule_t *rule) F_attribute_visibility_internal_d;
+ extern f_status_t controller_rule_setting_read(const controller_global_t global, const bool is_normal, const controller_setting_t setting, controller_cache_t *const cache, controller_rule_t * const rule) F_attribute_visibility_internal_d;
#endif // _di_controller_rule_setting_read_
/**
*
* This automatically sets the rule's status to F_complete.
*
+ * @param global
+ * The global data.
* @param rule
* The rule to process.
* @param action
* If no bits set, then operate normally in a synchronous manner.
* If bit controller_process_option_simulate_d, then the rule execution is in simulation mode (printing a message that the rule would be executed but does not execute the rule).
* If bit controller_process_option_asynchronous_d, then run asynchronously.
- * @param global
- * The global data.
* @param cache
* A structure for containing and caching relevant data.
*/
#ifndef _di_controller_rule_validate_
- extern void controller_rule_validate(const controller_rule_t rule, const uint8_t action, const uint8_t options, const controller_global_t global, controller_cache_t *cache) F_attribute_visibility_internal_d;
+ extern void controller_rule_validate(const controller_global_t global, const controller_rule_t rule, const uint8_t action, const uint8_t options, controller_cache_t * const cache) F_attribute_visibility_internal_d;
#endif // _di_controller_rule_validate_
/**
* Wait until all currently running Rule processes are complete.
*
+ * @param global
+ * The global data.
* @param is_normal
* If TRUE, then process as if this operates during a normal operation (entry and control).
* If FALSE, then process as if this operates during a an exit operation.
* This is ignored when caller is not NULL.
- * @param global
- * The global data.
* @param required
* If TRUE, then only process required rules and if a required rule has failed, return.
* If FALSE, process all waits, returning normally (required rules still result in failure).
* F_require (with error bit set) if a required process is in failed status when required is TRUE.
*/
#ifndef _di_controller_rule_wait_all_
- extern f_status_t controller_rule_wait_all(const bool is_normal, const controller_global_t global, const bool required, controller_process_t *caller) F_attribute_visibility_internal_d;
+ extern f_status_t controller_rule_wait_all(const controller_global_t global, const bool is_normal, const bool required, controller_process_t * const caller) F_attribute_visibility_internal_d;
#endif // _di_controller_rule_wait_all_
/**
* Wait until all currently running Rule processes are complete for some process type.
*
- * @param type
- * The process type to use when checking if thread is enabled.
* @param global
* The global data.
+ * @param type
+ * The process type to use when checking if thread is enabled.
* @param required
* If TRUE, then only process required rules and if a required rule has failed, return.
* If FALSE, process all waits, returning normally.
* @see controller_rule_wait_all()
*/
#ifndef _di_controller_rule_wait_all_process_type_
- extern f_status_t controller_rule_wait_all_process_type(const uint8_t type, const controller_global_t global, const bool required, controller_process_t *caller) F_attribute_visibility_internal_d;
+ extern f_status_t controller_rule_wait_all_process_type(const controller_global_t global, const uint8_t type, const bool required, controller_process_t * const caller) F_attribute_visibility_internal_d;
#endif // _di_controller_rule_wait_all_process_type_
#ifdef __cplusplus
fl_print_format("%[' failed due to a failure to setup the '%]%[", print->to.stream, print->context, print->context, print->notable);
if (status == F_control_group) {
- f_print_terminated(controller_control_group_s, print->to.stream);
+ f_print_terminated(controller_cgroup_s, print->to.stream);
}
else if (status == F_limit) {
f_print_terminated(controller_limit_s, print->to.stream);
#endif // _di_controller_rule_item_print_error_rule_not_loaded_
#ifndef _di_controller_rule_setting_read_print_error_
- void controller_rule_setting_read_print_error(const fl_print_t print, const f_string_t message, const f_array_length_t index, const f_array_length_t line_item, controller_thread_t *thread, controller_cache_t *cache) {
+ void controller_rule_setting_read_print_error(const fl_print_t print, const f_string_t message, const f_array_length_t index, const f_array_length_t line_item, controller_thread_t * const thread, controller_cache_t * const cache) {
if (print.verbosity == f_console_verbosity_quiet_e) return;
- // get the current line number within the settings item.
+ // Get the current line number within the settings item.
cache->action.line_item = line_item;
f_fss_count_lines(cache->buffer_item, cache->object_actions.array[index].start, &cache->action.line_item);
#endif // _di_controller_rule_setting_read_print_error_
#ifndef _di_controller_rule_setting_read_print_error_with_range_
- void controller_rule_setting_read_print_error_with_range(const fl_print_t print, const f_string_t before, const f_string_range_t range, const f_string_t after, const f_array_length_t index, const f_array_length_t line_item, controller_thread_t *thread, controller_cache_t *cache) {
+ void controller_rule_setting_read_print_error_with_range(const fl_print_t print, const f_string_t before, const f_string_range_t range, const f_string_t after, const f_array_length_t index, const f_array_length_t line_item, controller_thread_t * const thread, controller_cache_t * const cache) {
if (print.verbosity == f_console_verbosity_quiet_e) return;
- // get the current line number within the settings item.
+ // Get the current line number within the settings item.
cache->action.line_item = line_item;
f_fss_count_lines(cache->buffer_item, cache->object_actions.array[index].start, &cache->action.line_item);
controller_lock_print(print.to, thread);
- fl_print_format("%c%[%SRule setting %S '%]", print.to.stream, f_string_eol_s[0], print.context, print.prefix, before, print.context);
+ fl_print_format("%c%[%SRule setting%S '%]", print.to.stream, f_string_eol_s[0], print.context, print.prefix, before, print.context);
fl_print_format("%[%/Q%]", print.to.stream, print.notable, cache->buffer_item, range, print.notable);
fl_print_format("%['%S.%]%c", print.to.stream, print.context, after, print.context, f_string_eol_s[0]);
#endif // _di_controller_rule_setting_read_print_value_
#ifndef _di_controller_rule_setting_read_print_values_
- void controller_rule_setting_read_print_values(const controller_global_t global, const f_string_t name, const f_array_length_t index, controller_cache_t *cache) {
+ void controller_rule_setting_read_print_values(const controller_global_t global, const f_string_t name, const f_array_length_t index, controller_cache_t * const cache) {
if (global.main->error.verbosity != f_console_verbosity_debug_e && !(global.main->error.verbosity == f_console_verbosity_verbose_e && global.main->parameters[controller_parameter_simulate_e].result == f_console_result_found_e)) {
return;
* @see controller_rule_setting_read()
*/
#ifndef _di_controller_rule_setting_read_print_error_
- extern void controller_rule_setting_read_print_error(const fl_print_t print, const f_string_t message, const f_array_length_t index, const f_array_length_t line_item, controller_thread_t *thread, controller_cache_t *cache) F_attribute_visibility_internal_d;
+ extern void controller_rule_setting_read_print_error(const fl_print_t print, const f_string_t message, const f_array_length_t index, const f_array_length_t line_item, controller_thread_t * const thread, controller_cache_t * const cache) F_attribute_visibility_internal_d;
#endif // _di_controller_rule_setting_read_print_error_
/**
- * Print a message about a rule setting problem, with additional messages about value.
+ * Print a message about a rule setting problem, with additional messages about the value.
*
* This is intended to be explicitly called by controller_rule_setting_read().
* This is intended only to be used for simple messages.
* @param print
* The error or warning output structure.
* @param before
- * The string to append to the message being printed (before the value).
+ * The string to add to the message being printed (before the value).
* @param range
* The range within the cache item buffer representing the value.
* @param after
- * The string to append to the message being printed (after the value).
+ * The string to add to the message being printed (after the value).
* @param index
* The position in the object actions cache representing the object.
* @param line_item
* @see controller_rule_setting_read()
*/
#ifndef _di_controller_rule_setting_read_print_error_with_range_
- extern void controller_rule_setting_read_print_error_with_range(const fl_print_t print, const f_string_t before, const f_string_range_t range, const f_string_t after, const f_array_length_t index, const f_array_length_t line_item, controller_thread_t *thread, controller_cache_t *cache) F_attribute_visibility_internal_d;
+ extern void controller_rule_setting_read_print_error_with_range(const fl_print_t print, const f_string_t before, const f_string_range_t range, const f_string_t after, const f_array_length_t index, const f_array_length_t line_item, controller_thread_t * const thread, controller_cache_t * const cache) F_attribute_visibility_internal_d;
#endif // _di_controller_rule_setting_read_print_error_with_range_
/**
* A structure for containing and caching relevant data.
*/
#ifndef _di_controller_rule_setting_read_print_values_
- extern void controller_rule_setting_read_print_values(const controller_global_t global, const f_string_t name, const f_array_length_t index, controller_cache_t *cache) F_attribute_visibility_internal_d;
+ extern void controller_rule_setting_read_print_values(const controller_global_t global, const f_string_t name, const f_array_length_t index, controller_cache_t * const cache) F_attribute_visibility_internal_d;
#endif // _di_controller_rule_setting_read_print_values_
#ifdef __cplusplus
--- /dev/null
+#include "controller.h"
+#include "private-common.h"
+#include "private-task.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.5
+ * Licenses: lgpl-2.1-or-later
+ */
+#ifndef _PRIVATE_task_h
+#define _PRIVATE_task_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _PRIVATE_task_h
--- /dev/null
+#include "controller.h"
+#include "private-common.h"
+#include "private-task.h"
+#include "private-task_print.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.5
+ * Licenses: lgpl-2.1-or-later
+ */
+#ifndef _PRIVATE_task_print_h
+#define _PRIVATE_task_print_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _PRIVATE_task_print_h
process = global->thread->processs.array[i];
- // if "active" has a read lock, then do not attempt to clean it.
+ // If "active" has a read lock, then do not attempt to clean it.
if (f_thread_lock_write_try(&process->active) != F_none) {
continue;
}
- // if "lock" has a read or write lock, then do not attempt to clean it.
+ // If "lock" has a read or write lock, then do not attempt to clean it.
if (f_thread_lock_write_try(&process->lock) != F_none) {
f_thread_unlock(&process->active);
continue;
}
- // if process is active or busy, then do not attempt to clean it.
+ // If process is active or busy, then do not attempt to clean it.
if (process->state == controller_process_state_active_e || process->state == controller_process_state_busy_e) {
f_thread_unlock(&process->active);
f_thread_unlock(&process->lock);
continue;
}
- // if process has a PID file, then it is running in the background, only cleanup if the PID file no longer exists.
+ // If process has a PID file, then it is running in the background, only cleanup if the PID file no longer exists.
if (process->path_pids.used) {
f_array_length_t j = 0;
f_thread_unlock(&process->lock);
- // close any still open thread.
+ // Close any still open thread.
if (process->id_thread) {
status = f_thread_join(process->id_thread, 0);
}
}
- // deallocate dynamic portions of the structure that are only ever needed while the process is running.
+ // Deallocate dynamic portions of the structure that are only ever needed while the process is running.
controller_cache_delete_simple(&process->cache);
f_type_array_lengths_resize(0, &process->stack);
- // shrink the childs array.
+ // Shrink the childs array.
if (process->childs.used) {
for (; process->childs.used; --process->childs.used) {
if (process->childs.array[process->childs.used]) break;
}
}
- // deallocate the PID files.
+ // Deallocate the PID files.
if (process->path_pids.used) {
process->path_pids.used = 0;
f_string_dynamics_resize(0, &process->path_pids);
}
- // deallocate any rules in the space that is declared to be unused.
+ // Deallocate any rules in the space that is declared to be unused.
if (i >= global->thread->processs.used) {
controller_rule_delete_simple(&process->rule);
}
controller_thread_t thread = controller_thread_t_initialize;
controller_global_t global = macro_controller_global_t_initialize(main, setting, &thread);
- // the global locks must be initialized, but only once, so initialize immediately upon allocation.
+ // The global locks must be initialized, but only once, so initialize immediately upon allocation.
status = controller_lock_create(&thread.lock);
if (F_status_is_error(status)) {
}
}
- // only make the rule and control threads available once any/all pre-processing and are completed.
+ // Only make the rule and control threads available once any/all pre-processing and are completed.
if (F_status_is_error_not(status) && status != F_failure && status != F_child && thread.enabled == controller_thread_enabled_e) {
if (main->parameters[controller_parameter_validate_e].result == f_console_result_none_e) {
- // wait for the entry thread to complete before starting the rule thread.
+ // Wait for the entry thread to complete before starting the rule thread.
controller_thread_join(&thread.id_rule);
if (thread.enabled && setting->mode == controller_setting_mode_service_e) {
controller_thread_join(&thread.id_signal);
}
else if (setting->mode == controller_setting_mode_program_e) {
- status = controller_rule_wait_all(F_true, global, F_false, 0);
+ status = controller_rule_wait_all(global, F_true, F_false, 0);
}
}
- controller_thread_process_cancel(F_true, controller_thread_cancel_call_e, &global, 0);
+ controller_thread_process_cancel(global, F_true, controller_thread_cancel_call_e, 0);
controller_thread_process_exit(&global);
controller_cache_t *cache = &entry->global->thread->cache;
f_status_t *status = &entry->global->thread->status;
- *status = controller_entry_read(F_true, *entry->global, cache);
-
+ *status = controller_entry_read(*entry->global, F_true, cache);
if (F_status_set_fine(*status) == F_interrupt) {
entry->setting->ready = controller_setting_ready_abort_e;
entry->setting->ready = controller_setting_ready_fail_e;
}
else if (*status != F_child) {
- *status = controller_entry_preprocess(F_true, *entry->global, cache);
+ *status = controller_entry_preprocess(*entry->global, F_true, cache);
}
if (F_status_is_error_not(*status) && *status != F_child) {
*status = F_status_set_error(F_available_not);
}
else {
- *status = controller_entry_process(F_false, F_true, entry->global, cache);
+ *status = controller_entry_process(*entry->global, F_false, F_true, cache);
if (F_status_is_error(*status)) {
entry->setting->ready = controller_setting_ready_fail_e;
if ((F_status_set_fine(*status) == F_execute || F_status_set_fine(*status) == F_require) && entry->global->setting->failsafe_enabled) {
const uint8_t original_enabled = entry->global->thread->enabled;
- // restore operating mode so that the failsafe can execute.
+ // Restore operating mode so that the failsafe can execute.
*status = f_thread_mutex_lock(&entry->global->thread->lock.alert);
if (F_status_is_error_not(*status)) {
f_thread_mutex_unlock(&entry->global->thread->lock.alert);
}
- // restart the signal thread to allow for signals while operating the failsafe Items.
+ // Restart the signal thread to allow for signals while operating the failsafe Items.
if (!entry->global->thread->id_signal) {
f_thread_create(0, &entry->global->thread->id_signal, &controller_thread_signal_normal, (void *) entry->global);
}
- const f_status_t status_failsafe = controller_entry_process(F_true, F_true, entry->global, cache);
+ const f_status_t status_failsafe = controller_entry_process(*entry->global, F_true, F_true, cache);
if (F_status_is_error(status_failsafe)) {
if (main->error.verbosity != f_console_verbosity_quiet_e) {
}
else {
- // restore operating mode to value prior to failsafe mode.
+ // Restore operating mode to value prior to failsafe mode.
*status = f_thread_mutex_lock(&entry->global->thread->lock.alert);
if (F_status_is_error_not(*status)) {
controller_cache_t *cache = &entry->global->thread->cache;
f_status_t *status = &entry->global->thread->status;
- *status = controller_entry_read(F_false, *entry->global, cache);
+ *status = controller_entry_read(*entry->global, F_false, cache);
if (F_status_set_fine(*status) == F_interrupt) {
entry->setting->ready = controller_setting_ready_abort_e;
entry->setting->ready = controller_setting_ready_done_e;
}
else if (*status != F_child) {
- *status = controller_entry_preprocess(F_false, *entry->global, cache);
+ *status = controller_entry_preprocess(*entry->global, F_false, cache);
}
if (F_status_is_error_not(*status) && *status != F_child && *status != F_file_found_not) {
if (main->parameters[controller_parameter_validate_e].result == f_console_result_none_e || main->parameters[controller_parameter_simulate_e].result == f_console_result_found_e) {
- *status = controller_entry_process(F_false, F_false, entry->global, cache);
+ *status = controller_entry_process(*entry->global, F_false, F_false, cache);
if (F_status_is_error(*status)) {
entry->setting->ready = controller_setting_ready_fail_e;
const uint8_t original_enabled = entry->global->thread->enabled;
- // restore operating mode so that the failsafe can execute.
+ // Restore operating mode so that the failsafe can execute.
if (F_status_set_fine(*status) == F_execute) {
*status = f_thread_mutex_lock(&entry->global->thread->lock.alert);
f_thread_mutex_unlock(&entry->global->thread->lock.alert);
}
- // restart the signal thread to allow for signals while operating the failsafe Items.
+ // Restart the signal thread to allow for signals while operating the failsafe Items.
if (!entry->global->thread->id_signal) {
f_thread_create(0, &entry->global->thread->id_signal, &controller_thread_signal_other, (void *) entry->global);
}
}
- const f_status_t status_failsafe = controller_entry_process(F_true, F_false, entry->global, cache);
+ const f_status_t status_failsafe = controller_entry_process(*entry->global, F_true, F_false, cache);
if (F_status_is_error(status_failsafe)) {
if (main->error.verbosity != f_console_verbosity_quiet_e) {
}
else {
- // restore operating mode to value prior to failsafe mode.
+ // Restore operating mode to value prior to failsafe mode.
*status = f_thread_mutex_lock(&entry->global->thread->lock.alert);
if (F_status_is_error_not(*status)) {
#endif
#ifndef _di_controller_thread_process_
- void controller_thread_process(const bool is_normal, controller_process_t *process) {
+ void controller_thread_process(const bool is_normal, controller_process_t * const process) {
{
controller_thread_t *thread = (controller_thread_t *) process->main_thread;
#endif // _di_controller_thread_process_
#ifndef _di_controller_thread_process_cancel_
- void controller_thread_process_cancel(const bool is_normal, const uint8_t by, controller_global_t *global, controller_process_t *caller) {
+ void controller_thread_process_cancel(const controller_global_t global, const bool is_normal, const uint8_t by, controller_process_t * const caller) {
- // only cancel when enabled.
- if (!controller_thread_is_enabled(is_normal, global->thread)) {
+ // Only cancel when enabled.
+ if (!controller_thread_is_enabled(is_normal, global.thread)) {
return;
}
- // use the alert lock to toggle enabled (being used as if it were a write like and signal lock).
- f_status_t status = f_thread_mutex_lock(&global->thread->lock.alert);
+ // Use the alert lock to toggle enabled (being used as if it were a write like and signal lock).
+ f_status_t status = f_thread_mutex_lock(&global.thread->lock.alert);
if (F_status_is_error(status)) {
- global->thread->enabled = controller_thread_enabled_not_e;
+ global.thread->enabled = controller_thread_enabled_not_e;
}
else {
if (by == controller_thread_cancel_execute_e) {
- global->thread->enabled = controller_thread_enabled_execute_e;
+ global.thread->enabled = controller_thread_enabled_execute_e;
}
else if (by == controller_thread_cancel_exit_e) {
- global->thread->enabled = controller_thread_enabled_not_e;
+ global.thread->enabled = controller_thread_enabled_not_e;
}
else if (by == controller_thread_cancel_exit_execute_e) {
- global->thread->enabled = controller_thread_enabled_exit_execute_e;
+ global.thread->enabled = controller_thread_enabled_exit_execute_e;
}
else {
- global->thread->enabled = controller_thread_enabled_exit_e;
+ global.thread->enabled = controller_thread_enabled_exit_e;
}
- f_thread_mutex_unlock(&global->thread->lock.alert);
+ f_thread_mutex_unlock(&global.thread->lock.alert);
}
f_array_length_t spent = 0;
f_array_length_t j = 0;
pid_t pid = 0;
- if (global->thread->id_cleanup) {
- f_thread_cancel(global->thread->id_cleanup);
- f_thread_join(global->thread->id_cleanup, 0);
+ if (global.thread->id_cleanup) {
+ f_thread_cancel(global.thread->id_cleanup);
+ f_thread_join(global.thread->id_cleanup, 0);
- global->thread->id_cleanup = 0;
+ global.thread->id_cleanup = 0;
}
- // the sigtimedwait() function that is run inside of signal must be interrupted via the f_thread_cancel().
- if (by != controller_thread_cancel_signal_e && global->thread->id_signal) {
- f_thread_cancel(global->thread->id_signal);
- f_thread_join(global->thread->id_signal, 0);
+ // The sigtimedwait() function that is run inside of signal must be interrupted via the f_thread_cancel().
+ if (by != controller_thread_cancel_signal_e && global.thread->id_signal) {
+ f_thread_cancel(global.thread->id_signal);
+ f_thread_join(global.thread->id_signal, 0);
- global->thread->id_signal = 0;
+ global.thread->id_signal = 0;
}
- for (; i < global->thread->processs.used; ++i) {
+ for (; i < global.thread->processs.used; ++i) {
- if (!global->thread->processs.array[i]) continue;
+ if (!global.thread->processs.array[i]) continue;
if (caller && i == caller->id) continue;
- process = global->thread->processs.array[i];
+ process = global.thread->processs.array[i];
- // do not cancel exit processes, when not performing "execute" during exit.
- if (process->type == controller_process_type_exit_e && global->thread->enabled != controller_thread_enabled_exit_execute_e) {
+ // Do not cancel exit processes, when not performing "execute" during exit.
+ if (process->type == controller_process_type_exit_e && global.thread->enabled != controller_thread_enabled_exit_execute_e) {
continue;
}
for (j = 0; j < process->childs.used; ++j) {
if (process->childs.array[j] > 0) {
- f_signal_send(global->thread->signal ? global->thread->signal : F_signal_termination, process->childs.array[j]);
+ f_signal_send(global.thread->signal ? global.thread->signal : F_signal_termination, process->childs.array[j]);
}
} // for
status = controller_file_pid_read(process->path_pids.array[j], &pid);
if (pid) {
- f_signal_send(global->thread->signal ? global->thread->signal : F_signal_termination, pid);
+ f_signal_send(global.thread->signal ? global.thread->signal : F_signal_termination, pid);
}
}
} // for
} // for
- for (i = 0; i < global->thread->processs.size && spent < controller_thread_exit_process_cancel_total_d; ++i) {
+ for (i = 0; i < global.thread->processs.size && spent < controller_thread_exit_process_cancel_total_d; ++i) {
- if (!global->thread->processs.array[i]) continue;
+ if (!global.thread->processs.array[i]) continue;
if (caller && i == caller->id) continue;
- process = global->thread->processs.array[i];
+ process = global.thread->processs.array[i];
- // do not cancel exit processes, when not performing "execute" during exit.
- if (process->type == controller_process_type_exit_e && global->thread->enabled != controller_thread_enabled_exit_execute_e) continue;
+ // Do not cancel exit processes, when not performing "execute" during exit.
+ if (process->type == controller_process_type_exit_e && global.thread->enabled != controller_thread_enabled_exit_execute_e) continue;
do {
if (!process->id_thread) break;
- f_thread_signal(process->id_thread, global->thread->signal ? global->thread->signal : F_signal_termination);
+ f_thread_signal(process->id_thread, global.thread->signal ? global.thread->signal : F_signal_termination);
controller_time(0, controller_thread_exit_process_cancel_wait_d, &time);
if (pid) {
- // a hackish way to determine if the pid exists while waiting.
+ // A hackish way to determine if the pid exists while waiting.
if (getpgid(pid) >= 0) {
time.tv_sec = 0;
time.tv_nsec = controller_thread_exit_process_cancel_wait_d;
}
} // for
- for (i = 0; i < global->thread->processs.size; ++i) {
+ for (i = 0; i < global.thread->processs.size; ++i) {
- if (!global->thread->processs.array[i]) continue;
+ if (!global.thread->processs.array[i]) continue;
if (caller && i == caller->id) continue;
- process = global->thread->processs.array[i];
+ process = global.thread->processs.array[i];
- // do not kill exit processes, when not performing "execute" during exit.
- if (process->type == controller_process_type_exit_e && global->thread->enabled != controller_thread_enabled_exit_execute_e) continue;
+ // Do not kill exit processes, when not performing "execute" during exit.
+ if (process->type == controller_process_type_exit_e && global.thread->enabled != controller_thread_enabled_exit_execute_e) continue;
if (process->id_thread) {
if (process->childs.used) {
if (global->setting->ready == controller_setting_ready_done_e) {
- // the exit processing runs using the entry thread.
+ // The exit processing runs using the entry thread.
if (global->thread->id_entry) {
f_thread_cancel(global->thread->id_entry);
f_thread_join(global->thread->id_entry, 0);
global->thread->id_entry = 0;
}
- // restart the signal thread to allow for signals while operating the Exit.
+ // Restart the signal thread to allow for signals while operating the Exit.
if (!global->thread->id_signal) {
f_thread_create(0, &global->thread->id_signal, &controller_thread_signal_other, (void *) global);
}
}
}
- // the sigtimedwait() function that is run inside of signal must be interrupted via the f_thread_cancel().
+ // The sigtimedwait() function that is run inside of signal must be interrupted via the f_thread_cancel().
if (global->thread->id_signal) {
f_thread_cancel(global->thread->id_signal);
f_thread_join(global->thread->id_signal, 0);
global->thread->id_signal = 0;
}
- controller_thread_process_cancel(F_false, controller_thread_cancel_exit_e, global, 0);
+ controller_thread_process_cancel(*global, F_false, controller_thread_cancel_exit_e, 0);
}
else {
if (F_status_is_error_not(f_thread_mutex_lock(&global->thread->lock.alert))) {
* @see controller_rule_process_do()
*/
#ifndef _di_controller_thread_process_
- extern void controller_thread_process(const bool is_normal, controller_process_t *process) F_attribute_visibility_internal_d;
+ extern void controller_thread_process(const bool is_normal, controller_process_t * const process) F_attribute_visibility_internal_d;
#endif // _di_controller_thread_process_
/**
* Cancel all process threads.
*
+ * @param global
+ * The global thread data.
* @param is_normal
* If TRUE, then process as if this operates during a normal operation (entry and control).
* If FALSE, then process as if this operates during a an exit operation.
* If controller_thread_cancel_signal_e, then this was called from within the signal handling thread, so do not cancel the signal thread.
* If controller_thread_cancel_call_e, then this was not called from within the signal handling thread, so cancel the signal thread.
* If controller_thread_cancel_execute_e, then this was called from within the Entry/Exit for executing a process, so cancel the signal thread but not the Entry thread.
- * @param global
- * The global thread data.
* @param caller
* (optional) The process that is calling the cancel so that this process itself does not get cancelled.
* Set to NULL to not use.
*/
#ifndef _di_controller_thread_process_cancel_
- extern void controller_thread_process_cancel(const bool is_normal, const uint8_t by, controller_global_t *global, controller_process_t *caller) F_attribute_visibility_internal_d;
+ extern void controller_thread_process_cancel(const controller_global_t global, const bool is_normal, const uint8_t by, controller_process_t * const caller) F_attribute_visibility_internal_d;
#endif // _di_controller_thread_process_cancel_
/**
if (information.si_signo == F_signal_interrupt || information.si_signo == F_signal_abort || information.si_signo == F_signal_quit || information.si_signo == F_signal_termination) {
global->thread->signal = information.si_signo;
- controller_thread_process_cancel(is_normal, controller_thread_cancel_signal_e, global, 0);
+ controller_thread_process_cancel(*global, is_normal, controller_thread_cancel_signal_e, 0);
break;
}
f_pipe
f_print
f_signal
+f_socket
f_thread
fl_console
fl_control_group
build_libraries-individual -lfll_control_group -lfll_error -lfll_execute -lfll_fss -lfll_path -lfll_print -lfll_program
build_libraries-individual -lfl_console -lfl_control_group -lfl_conversion -lfl_directory -lfl_environment -lfl_fss -lfl_iki -lfl_print -lfl_string
-build_libraries-individual -lf_account -lf_capability -lf_color -lf_console -lf_control_group -lf_conversion -lf_directory -lf_environment -lf_execute -lf_file -lf_fss -lf_iki -lf_limit -lf_memory -lf_path -lf_pipe -lf_print -lf_signal -lf_status_string -lf_string -lf_thread -lf_type_array -lf_utf
+build_libraries-individual -lf_account -lf_capability -lf_color -lf_console -lf_control_group -lf_conversion -lf_directory -lf_environment -lf_execute -lf_file -lf_fss -lf_iki -lf_limit -lf_memory -lf_path -lf_pipe -lf_print -lf_signal -lf_socket -lf_status_string -lf_string -lf_thread -lf_type_array -lf_utf
build_libraries-level -lfll_2 -lfll_1 -lfll_0
build_libraries-monolithic -lfll
build_libraries_shared
build_libraries_static
-
build_sources_library controller.c private-common.c private-process.c
-build_sources_library private-control.c private-control_print.c private-controller.c private-controller_print.c private-entry.c private-entry_print.c private-lock.c private-lock_print.c private-rule.c private-rule_print.c
+build_sources_library common/private-cache.c common/private-lock.c common/private-rule.c common/private-task.c common/private-process.c common/private-entry.c common/private-setting.c common/private-thread.c
+build_sources_library private-control.c private-controller.c private-entry.c private-rule.c private-task.c
+build_sources_library private-control_print.c private-controller_print.c private-entry_print.c private-lock.c private-lock_print.c private-rule_print.c private-task_print.c
build_sources_library private-thread.c private-thread_control.c private-thread_entry.c private-thread_process.c private-thread_rule.c private-thread_signal.c
-
build_sources_library_shared
build_sources_library_static
build_sources_program main.c
pid ready
show init
+ control init.socket
+ control_user 0
+ control_group 0
+ control_mode ug+rwx,o-rwx
+
+task:
+ reboot system reboot
+ shutdown system shutdown
+
main:
timeout start 7
timeout stop 7
start boot root require
start boot proc asynchronous require
start boot devices asynchronous require
- start boot filesystem asynchronous
+ start boot file system asynchronous
start boot modules wait
start service logger
# fss-0005
+#
+# This example shows how htop can be started during the exit process rather than the entry.
+# See the htop-alternate.exit example.
setting:
mode program
+ control htop.socket
+ control_user 0
+ control_group 0
+ control_mode ug+rwx,o-rwx
+
main:
start serial s_1 asynchronous
start serial s_2 asynchronous
setting:
mode program
+ control htop.socket
+ control_user 0
+ control_group 0
+ control_mode ug+rwx,o-rwx
+
main:
start command htop
setting:
mode program
+ control htop.socket
+ control_user 0
+ control_group 0
+ control_mode ug+rwx,o-rwx
+
main:
failsafe start_top
# fss-0005
-
-setting:
- mode program
+#
+# This example shows how htop can be started during the exit process rather than the entry.
+# See the htop-alternate.entry example.
main:
failsafe "start top"
# fss-000d
#
-# Rule for initializing the /dev filesystem.
+# Rule for initializing the /dev file system.
#
setting:
- name "Setup /dev filesystem"
+ name "Setup /dev file system"
on start need boot root
-# Newer kernels automount a devpts filesystem on /dev, so this may not be needed.
+# Newer kernels automount a devpts file system on /dev, so this may not be needed.
#command:
# start mount /dev
--- /dev/null
+# fss-000d
+#
+# Task for rebooting the system.
+#
+# Todo: the idea here is that the controller program supports time based triggers triggers, which includes having status and being able to be canceled.
+# Todo: Another idea here is reboot is a separate program that goes into the background like a server when given an "in" or "on", has a status, and can be canceled.
+
+setting:
+ name "Reboot System"
+ environment PATH
+ script sh
+
+argument:
+ in time unit
+ on date
+ status
+ cancel
+
+help:
+ This task reboots the system after stopping all controlled processes.
+
+ When no parameters are specified, the reboot happens immediately.
+
+ The following parameters are available:
+ - in [time] [unit]: Reboot after so many units of time have passed.
+ - on [date]: Reboot when a given date and time is reached.
+ - status: Get the current state of the reboot process.
+ - cancel: Cancel the current reboot process, if active.
+
+help in:
+ Reboot after a specified amount of time is reached.
+
+ This acts as a timeout that begins immediately upon execution.
+ Once the timeout is reached, reboot is performed.
+
+ This command requires two additional parameters:
+ 1) A whole number representing the time.
+ 2) A unit of measurement, which must be one of:
+ - millisecond.
+ - second.
+ - minute.
+ - hour.
+ - day.
+ - week.
+ - month.
+ - year.
+ - gigatime.
+ - megatime.
+ - kilotime.
+ - decatime.
+ - time.
+ - gigaepochtime.
+ - megaepochtime.
+ - kiloepochtime.
+ - decaepochtime.
+ - epochtime.
+
+help on:
+ Reboot when the specified date is reached.
+
+ This acts as a trigger that waits for the given date and time of the system clock to be reached.
+ If the clock is changed to on or after the specified date, this trigger is executed.
+
+ This command requires one additional parameter:
+ 1) A date in ISO-8601 format.
+
+ The date must be in ISO-8601 format, which looks like: "2006-08-14T02:34:56-06:00".
+ The timezone offset is optional and if it is not provided, UTC is assumed.
+ TODO: support Time units and date times: "2017:0000".
+
+ Both reboot "on" and reboot "in" may be specified.
+ In which case the first one to happen will result in the reboot.
+
+help status:
+ Get whether the reboot is in progress or not and the current settings, if any.
+
+help cancel:
+ Cancel an existing reboot process, if it is not too late.
+
+script:
+ in {
+ reboot in argument:"time" argument:"unit"
+ }
+
+ on {
+ reboot on argument:"date"
+ }
+
+ status {
+ reboot status
+ }
+
+ cancel {
+ reboot cancel
+ }
--- /dev/null
+# fss-000d
+#
+# Task for shutting down the system.
+
+setting:
+ name "Shutdown System"
+ environment PATH
+ script sh
+
+argument:
+ in time unit
+ on date
+ status
+ cancel
+
+help:
+ This task shuts down the system after stopping all controlled processes.
+
+ When no parameters are specified, the shutdown happens immediately.
+
+ The following parameters are available:
+ - in [time] [unit]: Shutdown after so many units of time have passed.
+ - on [date]: Shutdown when a given date and time is reached.
+ - status: Get the current state of the shutdown process.
+ - cancel: Cancel the current shutdown process, if active.
+
+help in:
+ Shutdown after a specified amount of time is reached.
+
+ This acts as a timeout that begins immediately upon execution.
+ Once the timeout is reached, shutdown is performed.
+
+ This command requires two additional parameters:
+ 1) A whole number representing the time.
+ 2) A unit of measurement, which must be one of:
+ - millisecond.
+ - second.
+ - minute.
+ - hour.
+ - day.
+ - week.
+ - month.
+ - year.
+ - gigatime.
+ - megatime.
+ - kilotime.
+ - decatime.
+ - time.
+ - gigaepochtime.
+ - megaepochtime.
+ - kiloepochtime.
+ - decaepochtime.
+ - epochtime.
+
+help on:
+ Shutdown when the specified date is reached.
+
+ This acts as a trigger that waits for the given date and time of the system clock to be reached.
+ If the clock is changed to on or after the specified date, this trigger is executed.
+
+ This command requires one additional parameter:
+ 1) A date in ISO-8601 format.
+
+ The date must be in ISO-8601 format, which looks like: "2006-08-14T02:34:56-06:00".
+ The timezone offset is optional and if it is not provided, UTC is assumed.
+ TODO: support Time units and date times: "2017:0000", "2017::0000".
+
+ Both shutdown "on" and shutdown "in" may be specified.
+ In which case the first one to happen will result in the shutdown.
+
+help status:
+ Get whether the shutdown is in progress or not and the current settings, if any.
+
+help cancel:
+ Cancel an existing shutdown process, if it is not too late.
+
+script:
+ in {
+ shutdown in argument:"time" argument:"unit"
+ }
+
+ on {
+ shutdown on argument:"date"
+ }
+
+ status {
+ shutdown status
+ }
+
+ cancel {
+ shutdown cancel
+ }
These actions should be usable by any "control" program that communicates with this "controller" program.
Should any "control" or "controller" program implementation not support any particular Action for any reason, one should report that the Action is unsupported.
- Freeze Action\:
+ - Freeze Action\:
The Freeze Action is an extension of a Control Group.
This is internal to the "controller" program and is not customizable via any Rule file.
For a customizable "freeze"-like capability, look into the Pause and Resume Actions.
This must not attempt to freeze (or unfreeze) the Control Group that the "controller" belongs to.
Therefore, if a Rule does not specify a Control Group, then it is likely that the Freeze Action will be unsupported for that Rule/Control Group.
- Kill Action\:
+ - Kill Action\:
Forcefully terminate some process controlled by the "controller".
This action cannot be blocked and it is recommended to use a Stop Action instead for a more proper termination.
- Pause Action\:
+ - Pause Action\:
The Pause Action will pause (or freeze) the process controlled by the Rule.
Although similar to the Freeze Action, this is intended to communicate to an individual process and inform to Pause.
This is complemented by the Resume Action.
- Restart Action\:
+ - Restart Action\:
The Restart Action will either perform a Stop Action and then a Restart Action or it will perform the Restart Action designated in some Rule file.
Ideally this should inform some process to perform its own restart routines.
- Resume Action\:
+ - Resume Action\:
The Resume Action will unpause (or unfreeze) the process controlled by the Rule.
Although similar to the Thaw Action, this is intended to communicate to an individual process and inform to Resume.
This is complemented by the Pause Action.
- Reload Action\:
+ - Reload Action\:
The Reload Action will perform the Reload Action designated in some Rule file.
Ideally this should inform some process to perform its own reload routines.
Many programs often differentiate the concept "reload" from the concept "restart" in that the program remains running during a "reload".
- Start Action\:
+ - Start Action\:
The Start Action will perform the Start Action designated in some Rule file.
This action should be used to start some program or script.
This is the action called by Entry file.
This is complemented by the Stop Action.
- Stop Action\:
+ - Stop Action\:
The Stop Action will perform the Stop Action designated in some Rule file.
This action should be used to stop some program or script.
This is the action called for all running controlled processes on shutdown.
This is complemented by the Start Action.
- Thaw Action\:
+ - Thaw Action\:
The Thaw Action is an extension of a Control Group.
This is internal to the "controller" program and is not customizable via any Rule file.
For a customizable "thaw"-like capability, look into the "pause" and "resume" Actions.
# fss-0002
Entry Documentation:
- This describes the intent and purpose of the Entry file settings.
+ This describes the intent and purpose of an Entry file.
An Entry file, such as "default.entry", is intended to store a set of rules in which the controller will process on execution.
These are used to run some set of commands, such as booting a system.
All other Basic List Objects are not executed unless either an "item" or a "failsafe" specifies a valid Item name.
Execution of all Items are top-down.
- The "setting" item Object\:
+ - The "task" item Object\:
+ Represents tasks that are available for calling by some control program.
+ Each task has a name and a path.
+
+ - The "setting" item Object\:
Represents settings and is not an "item" that can be executed.
A number of settings are supported, but if this Item Object is not specified, then defaults are used.
The following settings are available: "mode", "pid", "session", and "show".
- The "mode" setting\:
+ - The "mode" setting\:
Represents the mode in which the Entry is operating in.
The following modes are supported: "program" and "service".
- The "program" mode\:
+ - The "program" mode\:
Designates that the Entry operates as a program and exits when complete.
Will call the "exit" with the same name as this Entry, but with the extension "exit", such as "default.exit".
Supports the Item Action "execute" to execute a program (switching the "controller" program entirely with the executed process).
- The "service" mode\:
+ - The "service" mode\:
Designates that the Entry operates as a service and will sit and wait for control commands when complete.
Will call the "exit" with the same name as this Entry, but with the extension "exit", such as "default.exit".
Does not support the Item Action "execute".
This is the default mode.
- The "pid" setting\:
+ - The "pid" setting\:
Represents how the entry pid file is generated or not.
The following modes are supported: "disable", "require", and "ready".
For "disable", not pid file representing the entry is created.
For "require", check to see if the PID file exists for an entry at startup and then when "ready" create a pid file, display error on pid file already exists or on failure and then fail.
For "ready", when "ready" create a pid file, display error on failure and then fail (does not check if PID file exists).
- The "session" setting\:
+ - The "session" setting\:
Represents the default way in which child processes are executed.
This default can be overriden by individual Rules.
For "new", Execute rule processes in a new session setting the process group to the executed process' id (making the executed process a "controlling terminal").
For "same", Execute rule processes in the same session where the process group is set to the parent process id.
- The "show" setting\:
+ - The "show" setting\:
Represents the way entry processing presents information to the screen.
This applies only to the entry and rule processing itself and does not handle the output of programs and scripts being executed by some entry or rule.
The following show options are supported: "normal" and "init".
For "normal", will not report the start or stop of some entry or rule execution but will report any errors or warnings as appropriate.
For "init", will report when starting programs and may include reporting success and failure status.
- The "item" item Object\:
+ - The "control" setting\:
+ Represents the path to the socket file in which the Controller uses to communicate over with clients such as a Control program.
+ A relative path is relative to the Controller PID directory.
+ An absolute path is treated exactly as the path given.
+ If no socket setting is specified, then no socket will be made available.
+ This socket file is only created once "ready" mode is achieved.
+
+ Providing "readonly" after the socket path instructs the Controller program not to create or delete the Socket file because the file system is assumed to be readonly.
+ The socket file itself must therefore already exist.
+ This should be possible in the cases of file systems that have pre-created a socket file at the designated path.
+ When "readonly", the group, mode, and user are also not processed effectively resulting in the "control_group", "control_mode", and "control_user" settings being ignored.
+
+ - The "control_group" setting\:
+ Represents the group name or group ID to assign to the socket file as the group.
+
+ - The "control_mode" setting\:
+ Represents the file mode assigned to the socket file.
+ This could either be the string version that might look like "u+rw-x,g+r-wx,o-rwx" or a numeric value like "0750".
+
+ - The "control_user" setting\:
+ Represents the user name or user ID to assign to the socket file as the owner.
+
+ - The "item" item Object\:
Each "item" supports the following Action Names: "consider", "execute", "failsafe", "freeze", "item", "kill", "pause", "reload", "restart", "ready", "resume", "start", "stop", and "timeout".
Of those types, the following are considered a "rule" Action: "freeze", "kill", "pause", "reload", "restart", "resume", "start", "stop", and "thaw".
- The "consider" Item Action\:
+ - The "consider" Item Action\:
A special case of a "rule" Action.
All Action Parameters are the same as with the "rule" Action Parameters.
The difference is that "consider" is only processed (instead of being processed and executed) and when some "rule" Action designates that this consideration is required (via "need"), wanted (via "want"), or wished for (via "wish") from the within the Rule file.
If this is determined to be executed, then this is immediately executed when needed, wanted or wished for and applies all properties as appropriate (such as "asynchronous", for example).
If this is determined not to be executed, then this "consider" is ignored as if it was never there in the first place.
- The "execute" Item Action\:
+ - The "execute" Item Action\:
Execute into the specified program.
On successfull execution, the controller program will no longer be running and will be replaced with the designated program.
This Item Action is only supported when operating in "program" mode.
- The "failsafe" Item Action\:
+ - The "failsafe" Item Action\:
Accepts only a valid Item Name in which will be executed when a failure is detected.
Only a single "failsafe" Item Action may function at a time.
Each successive "failsafe" Item Action specified replaces the previously defined "failsafe" Item Action (in a top-down manner).
When operating in "failsafe", the "require" Item Action is ignored (given that it is meaningless once operating in "failsafe" mode).
- The "freeze" Item Action\:
+ - The "freeze" Item Action\:
A "rule" Action for freezing some Control Group.
This Item Action will process the "freeze" inner Content of the named Rule.
This is specific to Control Groups and is not yet fully implemented.
Once implemented this documentation will need to be updated and clarified.
- The "item" Item Action\:
+ - The "item" Item Action\:
Accepts only a valid Item Name in which will be immediately executed.
Any valid Item Name, except for the reserved "main", may be used.
- The "kill" Item Action\:
+ - The "kill" Item Action\:
A "rule" Action for forcibly terminating some process.
This Item Action will process the "kill" inner Content of the named Rule.
- The "pause" Item Action\:
+ - The "pause" Item Action\:
A "rule" Action for pausing some process.
This Item Action will process the "pause" inner Content of the named Rule.
- The "reload" Item Action\:
+ - The "reload" Item Action\:
A "rule" Action for pausing some process.
This Item Action will process the "reload" inner Content of the named Rule.
- The "restart" Item Action\:
+ - The "restart" Item Action\:
A "rule" Action for pausing some process.
This Item Action will process the "restart" inner Content of the named Rule.
- The "resume" Item Action\:
+ - The "resume" Item Action\:
A "rule" Action for pausing some process.
This Item Action will process the "resume" inner Content of the named Rule.
- The "ready" Item Action\:
+ - The "ready" Item Action\:
Instructs the controller program when it is safe to perform normal tasks, such as creating the pid file.
When not specified, the state is always assumed to be ready.
For example, the controller program may be used as a full blown "init" replacement and therefore may need to mount the /var/run/ directory.
If the pid file is created at program start, then the /var/run/controller.pid would be written before the /var/run/ directory is ready.
- This could be a problem, such as on a read-only filesystem the pid creation fails and controller bails out on error.
+ This could be a problem, such as on a read-only file system the pid creation fails and controller bails out on error.
Adding "ready" essentially specifies a point in time in the Entry in which things are expected to be safe for such basic operations.
When the optional "wait" is provided, then "ready" will wait for all currently started asynchronous processes to complete before operating.
- The "start" Item Action\:
+ - The "start" Item Action\:
A "rule" Action for pausing some process.
This Item Action will process the "start" inner Content of the named Rule.
- The "stop" Item Action\:
+ - The "stop" Item Action\:
A "rule" Action for pausing some process.
This Item Action will process the "stop" inner Content of the named Rule.
- The "thaw" Item Action\:
+ - The "thaw" Item Action\:
A "rule" Action for unfreezing some Control Group.
This Item Action will process the "thaw" inner Content of the named Rule.
This is specific to Control Groups and is not yet fully implemented.
Once implemented this documentation will need to be updated and clarified.
- The "timeout" Item Action\:
+ - The "timeout" Item Action\:
Provides default global settings for each of the three special situations: "kill", "start", and "stop".
Each of these may only have a single one exist at a time (one "kill", one "start", one "stop", and one "wait").
Each successive "timeout" Item Action, specific to each Action Name (such as "start"), specified replaces the previously defined "timeout" Action (in a top-down manner).
These are: "freeze", "kill", "pause", "reload", "restart", "resume", "start", "stop", and "thaw".
The "rule" Actions immediately execute a named rule file.
- The first Action Parameter represents the rule directory, which is a relative directory path the rule file is to be found.
- - Do not include leading or trailing slashes.
- - This is relative to the settings rules directory.
- The second Action Parameter represents the basename for the rule file, without the file extension.
- - This must not have any directory paths.
- The remaining Action Parameters may be specified in any order\:
- - "asynchronous": Designates that execution will not block (wait).
- - "require": Designates that this rule must succeed or trigger execution of failsafe.
- - "wait": Designates that this rule will not execute until all other Actions before this (including "asynchronous" ones) finish executing (in a top-down manner).
+ - The first Action Parameter represents the rule directory, which is a relative directory path the rule file is to be found.
+ - Do not include leading or trailing slashes.
+ - This is relative to the settings rules directory.
+
+ - The second Action Parameter represents the basename for the rule file, without the file extension.
+ - This must not have any directory paths.
+
+ - The remaining Action Parameters may be specified in any order\:
+ - "asynchronous": Designates that execution will not block (wait).
+ - "require": Designates that this rule must succeed or trigger execution of failsafe.
+ - "wait": Designates that this rule will not execute until all other Actions before this (including "asynchronous" ones) finish executing (in a top-down manner).
The full path to the "rule" is relative to the settings, such that if the controller rule settings are found in "/etc/controller/rules/", then for a directory called "[directory]" and a rule basename of "[basename]", the resulting path would be: "/etc/controller/rules/[directory]/[basename].rule"
# fss-0002
Exit Documentation:
- This describes the intent and purpose of the Exit file settings.
+ This describes the intent and purpose of an Exit file.
An Exit file, such as "default.exit", is intended to store a set of rules in which the controller will process on execution.
These are used to run some set of commands, such as shutting down a system.
- The "setting" Item Object\:
+ - The "setting" Item Object\:
Represents settings and is not an "item" that can be executed.
A number of settings are supported, but if this Item Object is not specified, then defaults are used.
The following settings are available: "pid" and "show".
- The "pid" setting\:
+ - The "pid" setting\:
Represents how the entry pid file is generated or not.
The following modes are supported: "disable", "require", and "ready".
For "disable", not pid file representing the entry is created.
For "require", check to see if the PID file exists for an entry at startup and then when "ready" create a pid file, display error on pid file already exists or on failure and then fail.
For "ready", when "ready" create a pid file, display error on failure and then fail (does not check if PID file exists).
- The "show" setting\:
+ - The "show" setting\:
Represents the way entry processing presents information to the screen.
This applies only to the entry and rule processing itself and does not handle the output of programs and scripts being executed by some entry or rule.
The following show options are supported: "normal" and "init".
For "normal", will not report the start or stop of some entry or rule execution but will report any errors or warnings as appropriate.
For "init", will report when starting programs and may include reporting success and failure status.
- The "main" Item Object\:
+ - The "main" Item Object\:
Is always executed first (Therefore "main" is both reserved and required).
All other Basic List Objects are not executed unless either an "item" or a "failsafe" specifies a valid Item name.
Execution of all Items are top-down.
Each "item" supports the following Action Names: "consider", "execute", "failsafe", "freeze", "item", "kill", "pause", "reload", "restart", "ready", "resume", "start", "stop", and "timeout".
Of those types, the following are considered a "rule" Action: "freeze", "kill", "pause", "reload", "restart", "resume", "start", "stop", and "thaw".
- The "consider" Item Action\:
+ - The "consider" Item Action\:
A special case of a "rule" Action.
All Action Parameters are the same as with the "rule" Action Parameters.
The difference is that "consider" is only processed (instead of being processed and executed) and when some "rule" Action designates that this consideration is required (via "need"), wanted (via "want"), or wished for (via "wish") from the within the Rule file.
If this is determined to be executed, then this is immediately executed when needed, wanted or wished for and applies all properties as appropriate (such as "asynchronous", for example).
If this is determined not to be executed, then this "consider" is ignored as if it was never there in the first place.
- The "execute" Item Action\:
+ - The "execute" Item Action\:
Execute into the specified program.
On successfull execution, the controller program will no longer be running and will be replaced with the designated program.
This Item Action is only supported when operating in "program" mode.
- The "failsafe" Item Action\:
+ - The "failsafe" Item Action\:
Accepts only a valid Item Name in which will be executed when a failure is detected.
Only a single "failsafe" Item Action may function at a time.
Each successive "failsafe" Item Action specified replaces the previously defined "failsafe" Item Action (in a top-down manner).
When operating in "failsafe", the "require" Item Action is ignored (given that it is meaningless once operating in "failsafe" mode).
- The "freeze" Item Action\:
+ - The "freeze" Item Action\:
A "rule" Action for freezing some Control Group.
This Item Action will process the "freeze" inner Content of the named Rule.
This is specific to Control Groups and is not yet fully implemented.
Once implemented this documentation will need to be updated and clarified.
- The "item" Item Action\:
+ - The "item" Item Action\:
Accepts only a valid Item Name in which will be immediately executed.
Any valid Item Name, except for the reserved "main", may be used.
- The "kill" Item Action\:
+ - The "kill" Item Action\:
A "rule" Action for forcibly terminating some process.
This Item Action will process the "kill" inner Content of the named Rule.
- The "pause" Item Action\:
+ - The "pause" Item Action\:
A "rule" Action for pausing some process.
This Item Action will process the "pause" inner Content of the named Rule.
- The "reload" Item Action\:
+ - The "reload" Item Action\:
A "rule" Action for pausing some process.
This Item Action will process the "reload" inner Content of the named Rule.
- The "restart" Item Action\:
+ - The "restart" Item Action\:
A "rule" Action for pausing some process.
This Item Action will process the "restart" inner Content of the named Rule.
- The "resume" Item Action\:
+ - The "resume" Item Action\:
A "rule" Action for pausing some process.
This Item Action will process the "resume" inner Content of the named Rule.
- The "ready" Action\:
+ - The "ready" Action\:
Instructs the controller program when it is safe to perform normal tasks, such as creating the pid file.
When not specified, the state is always assumed to be ready.
For example, the controller program may be used as a full blown "init" replacement and therefore may need to mount the /var/run/ directory.
If the pid file is created at program start, then the /var/run/controller.pid would be written before the /var/run/ directory is ready.
- This could be a problem, such as on a read-only filesystem the pid creation fails and controller bails out on error.
+ This could be a problem, such as on a read-only file system the pid creation fails and controller bails out on error.
Adding "ready" essentially specifies a point in time in the Entry in which things are expected to be safe for such basic operations.
When the optional "wait" is provided, then "ready" will wait for all currently started asynchronous processes to complete before operating.
- The "start" Item Action\:
+ - The "start" Item Action\:
A "rule" Action for pausing some process.
This Item Action will process the "start" inner Content of the named Rule.
- The "stop" Item Action\:
+ - The "stop" Item Action\:
A "rule" Action for pausing some process.
This Item Action will process the "stop" inner Content of the named Rule.
- The "thaw" Item Action\:
+ - The "thaw" Item Action\:
A "rule" Action for unfreezing some Control Group.
This Item Action will process the "thaw" inner Content of the named Rule.
This is specific to Control Groups and is not yet fully implemented.
Once implemented this documentation will need to be updated and clarified.
- The "timeout" Item Action\:
+ - The "timeout" Item Action\:
Provides default global settings for each of the three special situations: "start", "stop", and "kill".
Each of these may only have a single one exist at a time (one "start", one "stop", and one "kill").
Each successive "timeout" Item Action, specific to each Action Name (such as "start"), specified replaces the previously defined "timeout" Action (in a top-down manner).
These are: "freeze", "kill", "pause", "reload", "restart", "resume", "start", "stop", and "thaw".
The "rule" Actions immediately execute a named rule file.
- The first Action Parameter represents the rule directory, which is a relative directory path the rule file is to be found.
- - Do not include leading or trailing slashes.
- - This is relative to the settings rules directory.
- The second Action Parameter represents the basename for the rule file, without the file extension.
- - This must not have any directory paths.
- The remaining Action Parameters may be specified in any order\:
- - "asynchronous": Designates that execution will not block (wait).
- - "require": Designates that this rule must succeed or trigger execution of failsafe.
- - "wait": Designates that this rule will not execute until all other Actions before this (including "asynchronous" ones) finish executing (in a top-down manner).
+ - The first Action Parameter represents the rule directory, which is a relative directory path the rule file is to be found.
+ - Do not include leading or trailing slashes.
+ - This is relative to the settings rules directory.
+
+ - The second Action Parameter represents the basename for the rule file, without the file extension.
+ - This must not have any directory paths.
+
+ - The remaining Action Parameters may be specified in any order\:
+ - "asynchronous": Designates that execution will not block (wait).
+ - "require": Designates that this rule must succeed or trigger execution of failsafe.
+ - "wait": Designates that this rule will not execute until all other Actions before this (including "asynchronous" ones) finish executing (in a top-down manner).
The full path to the "rule" is relative to the settings, such that if the controller rule settings are found in "/etc/controller/rules/", then for a directory called "[directory]" and a rule basename of "[basename]", the resulting path would be: "/etc/controller/rules/[directory]/[basename].rule"
# fss-0002
Rule Documentation:
- This describes the intent and purpose of the rule file settings.
+ This describes the intent and purpose of a Rule file.
- A rule file, such as "ssh.rule", is intended to designate what to execute.
+ A Rule file, such as "ssh.rule", is intended to designate what to execute.
The rule file is read top-down, except for the outer most list "setting", which is intended to store setting data for this rule.
Multiple outer most list Objects may be specified and they are executed as provided, in a top-down manner.
- The "setting" Rule Type has the following FSS-0001 (Extended) Content\:
+ - The "setting" Rule Type has the following FSS-0001 (Extended) Content\:
- "affinity": Define one or more processors to restrict this rule by with each number representing a specific processor by its id (starting at 0).
- "capability": Define a set of capabilities in which to use, using the capability "text" format (such as "= cap_chown+ep").
- - "control_group": Define a control group (cgroup) in which everything within this rule executes under.
+ - "cgroup": Define a cgroup (control group) 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. @todo make sure this is implemented.
- "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.
- "timeout": A set of timeouts to wait for in which to perform a set action or to consider failure.
- "user": A single user name or ID to execute as.
- In the case of "capability"\:
+ - In the case of "capability"\:
If the user the controller program is run as does not have the desired capabilities already, they cannot be added.
This essentially maintains or reduces the capabilities already available.
Due to capabilities only being a draft in the POSIX standard, one may expect "capabilities" support may not be available and in such a case this setting will do nothing.
If the dependent project (f_capability) does not have libcap support enabled, then capabilities will be unsupported by the compilation of this project.
- In the case of "control"\:
+ - 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"\:
+ - In the case of "group" and "user"\:
Only users and groups that the user the controller program is being run as is allowed to use may be used.
- In the case of "limit"\:
+ - In the case of "limit"\:
The first parameter must be one of: "as", "core", "cpu", "data", "fsize", "locks", "memlock", "msgqueue", "nice", "nofile", "nproc", "rss", "rtprio", "rttime", "sigpending", or "stack".
The second parameter repesents the soft limit.
The third parameter represents the hard limit.
This may be specified multiply times, but only once for each type.
- In the case of "on"\:
+ - In the case of "on"\:
The first parameter represents the Action the dependency exists under and must be one of: "freeze", "kill", "pause", "reload", "restart", "resume", "start", "stop", or "thaw".
The second parameter represents how the dependency is required and must be one of: "need", "want", or "wish".
The third parameter is a partial path to the rule file.
The fourth parameter represents the name of the rule file.
- In the case of the second parameter\:
- A "need" designates that the dependent rule is required to be executed (must exist and must succeed).
- A "want" designates that the dependent rule is to be executed (may exist and if it does, then it must succeed).
- A "wish" designates that the dependent rule is to be executed (may exist and if it does, but it does not need to succeed).
+ - In the case of the second parameter\:
+ - A "need" designates that the dependent rule is required to be executed (must exist and must succeed).
+ - A "want" designates that the dependent rule is to be executed (may exist and if it does, then it must succeed).
+ - A "wish" designates that the dependent rule is to be executed (may exist and if it does, but it does not need to succeed).
In the case of "want" and "wish", if the desired rule is either not found or is otherwise disabled, then this will not fail or otherwise block the wanting or wishing rule.
- In the case of "path"\:
+ - In the case of "path"\:
When specified, the PATH environment variable is automatically added to the "environment" setting.
- In the case of "parameter"\:
+ - In the case of "parameter"\:
IKI variables are expanded in a pre-process manner and will be removed prior to any execution.
Any IKI variables referencing an undefined parameter will be fully removed.
These parameters are only exposed in the specific rule file in which they are defined and cannot be shared between rules.
These IKI variables are only substituted within a Rule Item's Content (and not within a Rule Setting nor within a Rule Item's Object).
Note: IKI variables are not yet implemented.
- In the case of "scheduler"\:
+ - In the case of "scheduler"\:
The valid range of the priority number is dependent on the scheduler.
For example, non-real-time schedulers (such as "idle") only support a value of 0 whereas real-time schedulers (such as "fifo") only support an inclusive range of 1 to 99.
Supported non-real-time schedulers are: "batch", "idle", and "other" (aka: normal/default).
Supported real-time schedulers are: "deadline", "fifo", "round_robin".
- In the case of "timeout"\:
+ - In the case of "timeout"\:
The "timeout" Item Action provides default global settings for each of the three special situations: "kill", "start", and "stop".
Each of these may only have a single one exist at a time (one "kill", one "start", one "stop", and one "wait").
Each successive "timeout" Item Action, specific to each Action Name (such as "start"), specified replaces the previously defined "timeout" Action (in a top-down manner).
Commands are conditionally available depending on the presence of these, such as if "stop" is not provided then "stop" (and "restart") will not be available for the "control" program(s) to use.
Thee are additional Rule Actions not used to execute ("pid_file", "rerun", and "with")\:
- The "pid_file" Object's Content designates the path to the PID file created by the called program.
-
- The "rerun" Object's Content designates how to re-run a given execution Rule type.
- The first Content represents the execution type, which may be one of: "freeze", "kill", "pause", "reload", "restart", "resume", "start", "stop", and "thaw".
- The second Content represents when to run this re-run is triggered, which is either "success" (return code of 0) or "failure" (return code is not 0).
- The third Content and more represent additional options for fine tuning how the re-run is perforrmed\:
- When "delay", followed by a number of MegaTime (MT) (equivalent to milliseconds) in which to wait before attempting the re-run.
- When "max", followed by a positive number or the number 0 designating the maximum number of re-runs to perform.
- When "reset", the "max" re-run counter is reset for the opposite re-run when this re-run is triggered, such as\:
- A "rerun start success reset" and a "rerun failure max 10", the failure counter would reset to 0 when the "success" re-run is performed and not when the "failure" re-run is performed.
- A "max" of 0 designates that the re-run will happen infinitely.
-
- The "with" Object's Content designates special flags designating very specific behavior to be applied to any single Rule Type.
- The following flags are supported:
- - "full_path": Used only by Rule Types that execute something, wherein the entire full path is used for execution and is assigned as argument[0] (such as "/bin/bash").
- When not specified, the path provided is used and the argument[0] will be the base name (such as "bash").
- - "session_new": Execute in a new session setting the process group to the executed process' id (making the executed process a "controlling terminal").
- - "session_same": Execute in the same session where the process group is set to the parent process id.
+ - The "pid_file" Object's Content designates the path to the PID file created by the called program.
+
+ - The "rerun" Object's Content designates how to re-run a given execution Rule type.
+ - The first Content represents the execution type, which may be one of: "freeze", "kill", "pause", "reload", "restart", "resume", "start", "stop", and "thaw".
+
+ - The second Content represents when to run this re-run is triggered, which is either "success" (return code of 0) or "failure" (return code is not 0).
+
+ - The third Content and more represent additional options for fine tuning how the re-run is perforrmed\:
+ When "delay", followed by a number of MegaTime (MT) (equivalent to milliseconds) in which to wait before attempting the re-run.
+ When "max", followed by a positive number or the number 0 designating the maximum number of re-runs to perform.
+ When "reset", the "max" re-run counter is reset for the opposite re-run when this re-run is triggered, such as\:
+ A "rerun start success reset" and a "rerun failure max 10", the failure counter would reset to 0 when the "success" re-run is performed and not when the "failure" re-run is performed.
+
+ A "max" of 0 designates that the re-run will happen infinitely.
+
+ - The "with" Object's Content designates special flags designating very specific behavior to be applied to any single Rule Type.
+ The following flags are supported:
+ - "full_path": Used only by Rule Types that execute something, wherein the entire full path is used for execution and is assigned as argument[0] (such as "/bin/bash").
+ When not specified, the path provided is used and the argument[0] will be the base name (such as "bash").
+ - "session_new": Execute in a new session setting the process group to the executed process' id (making the executed process a "controlling terminal").
+ - "session_same": Execute in the same session where the process group is set to the parent process id.
The "controller" program is designed to support being run as an alternative to an init program (such as Sysvinit or SystemD).
To help prevent problems, simulation and validation functionality is provided.
- The "validate" functionality\:
+ - The "validate" functionality\:
By itself will simply check the syntax of the Entry and Rule files (for Rule files specified in the Entry or Exit file).
Errors are reported and nothing is executed.
The "controller" program will return 0 on validation success and 1 on validation failure.
- The "simulate" functionality\:
+ - The "simulate" functionality\:
By itself will perform a simulated execution of all Rules designated by an Entry or Exit file.
The simulation is not a true simulation in that no program is ever called to perform any operations.
Furthermore, any "script" specified inside a Rule is only simulated as a whole and not its individual parts.
Once the Entry file is finished executing, the "simulate" will continue to run waiting on "control" commands.
- The "simulate" with "validate" functionality\:
+ - The "simulate" with "validate" functionality\:
Will perform similar to "validate" functionality except that additional information of the Rules to be executed will be printed.
There will be neither execution nor simulated execution of any Rule when both "simulate" and "validate" are used together.
--- /dev/null
+# fss-0002
+
+Task Documentation:
+ This describes the intent and purpose of a Task file.
+
+ A Task file, such as "reboot.task", is intended to designate a command for a user-space program, such as "control", to execute.
+
+ The Task file is read top-down, except for the reserved outer most lists "argument", "help", and "setting".
+
+ Similar to a Rule Types, the Task file utilizes Task Types for performing the execution.
+
+ Unlike a Rule Type, the Task Type names are represented by the arguments passed to the task.
+
+ Each Task allows only a single execution instance.
+
+ The task "controller" is reserved for use by the Controller program and provides special commands for manipulating the Controller program.
+ These are:
+ - exit: Stop the Controller program and activate the exit cycle.
+ - rule: Perform a Rule-specific operations, such as starting and stopping a Rule. ([stop|start|etc..] rule [rule_path] [rule_name]).
+ - status: Get information about the Controller, a Task, or a Rule. (status, status rule [rule_path] [rule_name], status task [task_path] [task_name]).
+ When [rule_path] or [task_path] is not specified, all Rules or Tasks already loaded with this name are used.
+
+ The following reserved outer lists are available\:
+ - parameter.
+ - help.
+ - setting.
+
+ The following Task Types are supported:
+ - Command.
+ - Script.
+
+ Arguments describe parameters
+
+ The help outer list represents the message returned when help is requested.
- Each Action Content are the "Action Parameters".
The Items:
- "main": required.
+ - "main": required.
- "setting": optional, Actions may be one of:
+ - "command": optional.
+ Any valid Object represents a command name with\:
+ The first Content represents the file path (without any leading/trailing slashes and without file extension).
+ The second Content represent the basename of the command file.
+
+ - "setting": optional, Actions may be one of\:
- "mode": Exactly one Content that is one of "program" or "service".
- "pid": Exactly one Content that is one of "disable", "require", or "ready".
- - "session": Exactly one Content that is one of "new" or "same".
- - "show": Exactly one Content that is one of "normal" or "init".
+ - "session": Exactly one Content that is one of "new" or "same".
+ - "show": Exactly one Content that is one of "normal" or "init".
+ - "control": One to two Content.
+ The first Content is a relative or absolute path to a socket file.
+ The second Content an optional "readonly".
+ - "control_group": Exactly one Content that is a group name or group id.
+ - "control_mode": Exactly one Content that is a valid file mode.
+ - "control_user": Exactly one Content that is a user name or user id.
The Entry file may have any other valid Item Objects, but only the above are reserved.
The Actions\:
- "consider": One or more Content.
+ - "consider": One or more Content.
The first Content is the relative file path (without any leading/trailing slashes and without file extension).
The second Content is the basename for a rule file.
The third and beyond may only be one of\:
- "require"
- "wait"
- "execute": One or more Content.
+ - "execute": One or more Content.
The first Content is the program name or full path to the program (the program may be a script).
All remaining Content are passed as parameters to the program being executed.
- "failsafe": One Content that is a valid Object name, except for the reserved "main".
+ - "failsafe": One Content that is a valid Object name, except for the reserved "main".
- "freeze": Two or more Content.
+ - "freeze": Two or more Content.
The first Content that is the relative directory path (without any leading/trailing slashes).
The second Content that is the basename for a rule file.
The third and beyond may only be one of\:
- "require"
- "wait"
- "item": One Content that is a valid Object name, except for the reserved "main".
+ - "item": One Content that is a valid Object name, except for the reserved "main".
- "kill": Two or more Content.
+ - "kill": Two or more Content.
The first Content that is the relative directory path (without any leading/trailing slashes).
The second Content that is the basename for a rule file.
The third and beyond may only be one of\:
- "require"
- "wait"
- "pause": Two or more Content.
+ - "pause": Two or more Content.
The first Content that is the relative directory path (without any leading/trailing slashes).
The second Content that is the basename for a rule file.
The third and beyond may only be one of\:
- "require"
- "wait"
- "ready": Zero or One Content.
+ - "ready": Zero or One Content.
The first may only be one of\:
- "wait"
- "reload": Two or more Content.
+ - "reload": Two or more Content.
The first Content that is the relative directory path (without any leading/trailing slashes).
The second Content that is the basename for a rule file.
The third and beyond may only be one of\:
- "require"
- "wait"
- "restart": Two or more Content.
+ - "restart": Two or more Content.
The first Content that is the relative directory path (without any leading/trailing slashes).
The second Content that is the basename for a rule file.
The third and beyond may only be one of\:
- "require"
- "wait"
- "resume": Two or more Content.
+ - "resume": Two or more Content.
The first Content that is the relative directory path (without any leading/trailing slashes).
The second Content that is the basename for a rule file.
The third and beyond may only be one of\:
- "require"
- "wait"
- "start": Two or more Content.
+ - "start": Two or more Content.
The first Content that is the relative directory path (without any leading/trailing slashes).
The second Content that is the basename for a rule file.
The third and beyond may only be one of\:
- "require"
- "wait"
- "stop": Two or more Content.
+ - "stop": Two or more Content.
The first Content that is the relative directory path (without any leading/trailing slashes).
The second Content that is the basename for a rule file.
The third and beyond may only be one of\:
- "require"
- "wait"
- "thaw": Two or more Content.
+ - "thaw": Two or more Content.
The first Content that is the relative directory path (without any leading/trailing slashes).
The second Content that is the basename for a rule file.
The third and beyond may only be one of\:
- "require"
- "wait"
- "timeout": Two Content.
+ - "timeout": Two Content.
The first being one of\:
- "start"
- "stop"
- Each Action Content are the "Action Parameters".
The Items:
- "main": required.
+ - "main": required.
- "setting": optional, Actions may be one of:
+ - "setting": optional, Actions may be one of:
- "pid": Exactly one Content that is one of "disable", "require", or "ready".
- "session": Exactly one Content that is one of "new" or "same".
- "show": Exactly one Content that is one of "normal" or "init".
The Exit file may have any other valid Item Objects, but only the above are reserved.
The Actions\:
- "consider": One or more Content.
+ - "consider": One or more Content.
The first Content that is the relative file path (without any leading/trailing slashes and without file extension).
The second Content that is the basename for a rule file.
The third and beyond may only be one of\:
- "require"
- "wait"
- "failsafe": One Content that is a valid Object name, except for the reserved "main".
+ - "failsafe": One Content that is a valid Object name, except for the reserved "main".
- "freeze": Two or more Content.
+ - "freeze": Two or more Content.
The first Content that is the relative directory path (without any leading/trailing slashes).
The second Content that is the basename for a rule file.
The third and beyond may only be one of\:
- "require"
- "wait"
- "item": One Content that is a valid Object name, except for the reserved "main".
+ - "item": One Content that is a valid Object name, except for the reserved "main".
- "kill": Two or more Content.
+ - "kill": Two or more Content.
The first Content that is the relative directory path (without any leading/trailing slashes).
The second Content that is the basename for a rule file.
The third and beyond may only be one of\:
- "require"
- "wait"
- "pause": Two or more Content.
+ - "pause": Two or more Content.
The first Content that is the relative directory path (without any leading/trailing slashes).
The second Content that is the basename for a rule file.
The third and beyond may only be one of\:
- "require"
- "wait"
- "ready": Zero or One Content.
+ - "ready": Zero or One Content.
The first may only be one of\:
- "wait"
- "reload": Two or more Content.
+ - "reload": Two or more Content.
The first Content that is the relative directory path (without any leading/trailing slashes).
The second Content that is the basename for a rule file.
The third and beyond may only be one of\:
- "require"
- "wait"
- "restart": Two or more Content.
+ - "restart": Two or more Content.
The first Content that is the relative directory path (without any leading/trailing slashes).
The second Content that is the basename for a rule file.
The third and beyond may only be one of\:
- "require"
- "wait"
- "resume": Two or more Content.
+ - "resume": Two or more Content.
The first Content that is the relative directory path (without any leading/trailing slashes).
The second Content that is the basename for a rule file.
The third and beyond may only be one of\:
- "require"
- "wait"
- "start": Two or more Content.
+ - "start": Two or more Content.
The first Content that is the relative directory path (without any leading/trailing slashes).
The second Content that is the basename for a rule file.
The third and beyond may only be one of\:
- "require"
- "wait"
- "stop": Two or more Content.
+ - "stop": Two or more Content.
The first Content that is the relative directory path (without any leading/trailing slashes).
The second Content that is the basename for a rule file.
The third and beyond may only be one of\:
- "require"
- "wait"
- "thaw": Two or more Content.
+ - "thaw": Two or more Content.
The first Content that is the relative directory path (without any leading/trailing slashes).
The second Content that is the basename for a rule file.
The third and beyond may only be one of\:
- "require"
- "wait"
- "timeout": Two Content.
+ - "timeout": Two Content.
The first being one of\:
- "start"
- "stop"
The "setting" Rule Type has the following FSS-0001 (Extended)\:
- "affinity": One or more Content, each must be a 0 or greater whole number.
- "capability": One Content representing capabilities.
- - "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).
+ - "cgroup": Two or more Content, the first Content being either "existing" or "new" and the remaining representing a valid cgroup (control group) 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.
--- /dev/null
+# fss-0002
+
+Task Specification: