# fss-0000
-_di_libcap_ Disable libcap support, allow for compiling and linking without libcap (-lcap).
+_di_libcap_ Disable libcap support, allow for compiling and linking without libcap (-lcap).
_di_thread_support_ Disables thread support.
_libcap_legacy_only_ Disable functionality provided by later versions of libcap (2.43 and later).
-_override_controller_default_engine_ Provide a custom scripting engine name string to execute (such as php).
-_override_controller_default_engine_length_ The number of bytes representing the string in _override_controller_default_engine_ (not including the terminating NULL).
-_override_controller_path_pid_ Use this as the default custom directory path representing the location of the controller program pid.
-_override_controller_path_pid_length_ The number of bytes representing the string in _override_controller_path_pid_ (not including the terminating NULL).
-_override_controller_path_pid_prefix_ Use this as the default custom prefix prepended to the file name of the file representing the controller program pid.
-_override_controller_path_pid_prefix_length_ The number of bytes representing the string in _override_controller_path_pid_prefix_ (not including the terminating NULL).
-_override_controller_path_pid_suffix_ Use this as the default custom prefix prepended to the file name of the file representing the controller program pid.
-_override_controller_path_pid_suffix_length_ The number of bytes representing the string in _override_controller_path_pid_suffix_ (not including the terminating NULL).
-_override_controller_path_socket_ Use this as the default custom directory path representing the location of the controller program socket.
-_override_controller_path_socket_length_ The number of bytes representing the string in _override_controller_path_socket_ (not including the terminating NULL).
-_override_controller_path_socket_prefix_ Use this as the default custom prefix prepended to the file name of the file representing the controller program socket.
+
+_override_controller_default_engine_ Provide a custom scripting engine name string to execute (such as php).
+_override_controller_path_pid_ Use this as the default custom directory path representing the location of the controller program pid.
+_override_controller_path_pid_prefix_ Use this as the default custom prefix prepended to the file name of the file representing the controller program pid.
+_override_controller_path_pid_suffix_ Use this as the default custom prefix prepended to the file name of the file representing the controller program pid.
+_override_controller_path_settings_ Use this as the default custom settings path, such as /etc/settings.
+_override_controller_path_socket_ Use this as the default custom directory path representing the location of the controller program socket.
+_override_controller_path_socket_prefix_ Use this as the default custom prefix prepended to the file name of the file representing the controller program socket.
+_override_controller_path_socket_suffix_ Use this as the default custom prefix prepended to the file name of the file representing the controller program socket.
+
+_override_controller_default_engine_length_ The number of bytes representing the string in _override_controller_default_engine_ (not including the terminating NULL).
+_override_controller_path_pid_length_ The number of bytes representing the string in _override_controller_path_pid_ (not including the terminating NULL).
+_override_controller_path_pid_prefix_length_ The number of bytes representing the string in _override_controller_path_pid_prefix_ (not including the terminating NULL).
+_override_controller_path_pid_suffix_length_ The number of bytes representing the string in _override_controller_path_pid_suffix_ (not including the terminating NULL).
+_override_controller_path_settings_length_ The number of bytes representing the string in _override_controller_path_settings_ (not including the terminating NULL).
+_override_controller_path_socket_length_ The number of bytes representing the string in _override_controller_path_socket_ (not including the terminating NULL).
_override_controller_path_socket_prefix_length_ The number of bytes representing the string in _override_controller_path_socket_prefix_ (not including the terminating NULL).
-_override_controller_path_socket_suffix_ Use this as the default custom prefix prepended to the file name of the file representing the controller program socket.
_override_controller_path_socket_suffix_length_ The number of bytes representing the string in _override_controller_path_socket_suffix_ (not including the terminating NULL).
-_pthread_attr_unsupported_ Disable non-portable functionality associated with pthread_attr.
+_pthread_attr_unsupported_ Disable non-portable functionality associated with pthread_attr.
_pthread_sigqueue_unsupported_ Disable GNU specific sigqueue().
build_sources_library main/common.c main/common/define.c main/common/enumeration.c main/common/print.c main/common/string.c main/common/type.c
build_sources_library main/common/type/cache.c main/common/type/control.c main/common/type/entry.c main/common/type/lock.c main/common/type/process.c main/common/type/rule.c main/common/type/thread.c
build_sources_library main/common/string/general.c main/common/string/rule.c
-build_sources_library main/print/data.c main/print/debug.c main/print/error.c main/print/message.c main/print/verbose.c main/print/warning.c
+build_sources_library main/path.c
+build_sources_library main/print/data.c main/print/debug.c main/print/error.c main/print/lock.c main/print/message.c main/print/verbose.c main/print/warning.c
build_sources_library main/signal.c main/thread.c
build_sources_headers main/common.h main/controller.h main/common/define.h main/common/enumeration.h main/common/print.h main/common/string.h main/common/type.h
build_sources_headers main/common/enumeration/control.h main/common/enumeration/entry.h main/common/enumeration/process.h main/common/enumeration/rule.h main/common/enumeration/thread.h
build_sources_headers main/common/string/general.h main/common/string/rule.h
build_sources_headers main/common/type/cache.h main/common/type/control.h main/common/type/entry.h main/common/type/lock.h main/common/type/process.h main/common/type/rule.h main/common/type/thread.h
-build_sources_headers main/print/data.h main/print/debug.h main/print/error.h main/print/message.h main/print/verbose.h main/print/warning.h
+build_sources_headers main/path.h
+build_sources_headers main/print/data.h main/print/debug.h main/print/error.h main/print/lock.h main/print/message.h main/print/verbose.h main/print/warning.h
build_sources_headers main/signal.h main/thread.h
build_sources_documentation man
// FLL-1 includes.
#include <fll/level_1/conversion.h>
+#include <fll/level_1/path.h>
#include <fll/level_1/print.h>
// FLL-2 includes.
#include <program/controller/main/common/type/thread.h>
#include <program/controller/main/common/type.h>
#include <program/controller/main/common.h>
+#include <program/controller/main/path.h>
#include <program/controller/main/print/data.h>
#include <program/controller/main/print/debug.h>
#include <program/controller/main/print/error.h>
+#include <program/controller/main/print/lock.h>
#include <program/controller/main/print/message.h>
#include <program/controller/main/print/verbose.h>
#include <program/controller/main/print/warning.h>
data.program.pipe = fll_program_data_pipe_input_e;
}
+ data.setting.flag |= controller_main_flag_interruptible_e;
+
fll_program_standard_set_up(&data.program);
f_file_umask_get(&data.program.umask);
// FLL-1 includes.
#include <fll/level_1/conversion.h>
+#include <fll/level_1/path.h>
#include <fll/level_1/print.h>
// FLL-2 includes.
#include <program/controller/main/common/type/thread.h>
#include <program/controller/main/common/type.h>
#include <program/controller/main/common.h>
+#include <program/controller/main/path.h>
#include <program/controller/main/print/data.h>
#include <program/controller/main/print/debug.h>
#include <program/controller/main/print/error.h>
+#include <program/controller/main/print/lock.h>
#include <program/controller/main/print/message.h>
#include <program/controller/main/print/verbose.h>
#include <program/controller/main/print/warning.h>
data.program.pipe = fll_program_data_pipe_input_e;
}
+ data.setting.flag &= ~controller_main_flag_interruptible_e;
+ process.entry.pid = controller_entry_pid_disable_e;
+ process.entry.show = controller_entry_show_init_e;
+
fll_program_standard_set_up(&data.program);
f_file_umask_get(&data.program.umask);
#ifndef _di_controller_main_setting_load_
void controller_main_setting_load(const f_console_arguments_t arguments, controller_main_t * const main, controller_process_t * const process) {
- if (!main) return;
+ if (!main || !process) return;
main->setting.state.step_small = controller_allocation_console_d;
}
f_string_static_t * const args = main->program.parameters.arguments.array;
+ f_number_unsigned_t index = 0;
process->control.server.domain = f_socket_protocol_family_local_e;
process->control.server.type = f_socket_type_stream_e;
memset(&process->control.server.address, 0, sizeof(f_socket_address_t));
+ {
+ const uint8_t codes[] = {
+ controller_parameter_cgroup_e,
+ controller_parameter_daemon_e,
+ controller_parameter_pid_e,
+ controller_parameter_settings_e,
+ };
+
+ const f_string_static_t strings[] = {
+ controller_long_cgroup_s,
+ controller_long_daemon_s,
+ controller_long_pid_s,
+ controller_long_settings_s,
+ };
+
+ for (index = 0; index < 4; ++index) {
+
+ if (main->program.parameters.array[controller_parameter_settings_e].result & codes[index]) {
+ main->setting.state.status = F_status_set_error(F_parameter);
+
+ if ((main->setting.flag & controller_main_flag_print_first_e) && main->program.message.verbosity > f_console_verbosity_error_e) {
+ fll_print_dynamic_raw(f_string_eol_s, main->program.message.to);
+ }
+
+ fll_program_print_error_parameter_missing_value(&main->program.error, f_console_symbol_long_normal_s, strings[index]);
+
+ return;
+ }
+ } // for
+ }
+
// The first remaining argument represents the entry name.
main->setting.state.status = f_string_dynamic_append(main->program.parameters.remaining.used ? args[main->program.parameters.remaining.array[0]] : controller_default_s, &process->name_entry);
return;
}
+
+ process->path_setting.used = 0;
+
+ if (main->program.parameters.array[controller_parameter_settings_e].locations.used) {
+ index = main->program.parameters.array[controller_parameter_settings_e].values.array[main->program.parameters.array[controller_parameter_settings_e].values.used - 1];
+
+ controller_path_canonical_relative(main, process->path_current, args[index], &process->path_setting);
+ }
+ else {
+ main->setting.state.status = f_string_dynamic_append(controller_default_path_settings_s, &process->path_setting);
+ }
+
+ if (F_status_is_error(main->setting.state.status)) {
+ if ((main->setting.flag & controller_main_flag_print_first_e) && main->program.message.verbosity > f_console_verbosity_error_e) {
+ fll_print_dynamic_raw(f_string_eol_s, main->program.message.to);
+ }
+
+ if (main->program.parameters.array[controller_parameter_settings_e].locations.used) {
+ controller_main_print_error_file(&main->program.error, macro_controller_f(controller_path_canonical_relative), args[index], f_file_operation_verify_s, fll_error_file_type_path_e);
+ }
+ else {
+ controller_main_print_error(&main->program.error, macro_controller_f(f_string_dynamic_append));
+ }
+
+ return;
+ }
+
+ if (!process->path_pid.used && !main->program.parameters.array[controller_parameter_pid_e].locations.used) {
+ main->setting.state.status = f_string_dynamic_append(controller_default_path_pid_s, &process->path_pid);
+
+ if (F_status_is_error_not(main->setting.state.status)) {
+ main->setting.state.status = f_string_dynamic_append(f_path_separator_s, &process->path_pid);
+ }
+
+ if (F_status_is_error_not(main->setting.state.status)) {
+ main->setting.state.status = f_string_dynamic_append(controller_default_path_pid_prefix_s, &process->path_pid);
+ }
+
+ if (F_status_is_error_not(main->setting.state.status)) {
+ main->setting.state.status = f_string_dynamic_append(process->name_entry, &process->path_pid);
+ }
+
+ if (F_status_is_error_not(main->setting.state.status)) {
+ main->setting.state.status = f_string_dynamic_append(controller_default_path_pid_suffix_s, &process->path_pid);
+ }
+
+ if (F_status_is_error(main->setting.state.status)) {
+ if ((main->setting.flag & controller_main_flag_print_first_e) && main->program.message.verbosity > f_console_verbosity_error_e) {
+ fll_print_dynamic_raw(f_string_eol_s, main->program.message.to);
+ }
+
+ controller_main_print_error(&main->program.error, macro_controller_f(f_string_dynamic_append));
+
+ return;
+ }
+ }
+
+ if (main->program.parameters.array[controller_parameter_cgroup_e].locations.used) {
+ index = main->program.parameters.array[controller_parameter_cgroup_e].values.array[main->program.parameters.array[controller_parameter_cgroup_e].values.used - 1];
+
+ if (args[index].used) {
+ controller_path_canonical_relative(main, process->path_current, args[index], &process->path_cgroup);
+
+ if (F_status_is_error(main->setting.state.status)) {
+ if ((main->setting.flag & controller_main_flag_print_first_e) && main->program.message.verbosity > f_console_verbosity_error_e) {
+ fll_print_dynamic_raw(f_string_eol_s, main->program.message.to);
+ }
+
+ controller_main_print_error_file(&main->program.error, macro_controller_f(controller_path_canonical_relative), args[index], f_file_operation_verify_s, fll_error_file_type_path_e);
+
+ return;
+ }
+
+ main->setting.state.status = f_string_append_assure(F_path_separator_s, 1, &process->path_cgroup);
+
+ if (F_status_is_error(main->setting.state.status)) {
+ if ((main->setting.flag & controller_main_flag_print_first_e) && main->program.message.verbosity > f_console_verbosity_error_e) {
+ fll_print_dynamic_raw(f_string_eol_s, main->program.message.to);
+ }
+
+ controller_main_print_error(&main->program.error, macro_controller_f(f_string_append_assure));
+
+ return;
+ }
+ }
+ else {
+ controller_main_print_debug_directory_path_empty(&main->program.warning, f_console_symbol_long_normal_s, controller_long_cgroup_s);
+ }
+ }
+
+ if (main->program.parameters.array[controller_parameter_interruptible_e].result & f_console_result_found_e) {
+ if (main->program.parameters.array[controller_parameter_uninterruptible_e].result & f_console_result_found_e) {
+ if (main->program.parameters.array[controller_parameter_interruptible_e].location < main->program.parameters.array[controller_parameter_uninterruptible_e].location) {
+ main->setting.flag &= ~controller_main_flag_interruptible_e;
+ }
+ else {
+ main->setting.flag |= controller_main_flag_interruptible_e;
+ }
+ }
+ else {
+ main->setting.flag |= controller_main_flag_interruptible_e;
+ }
+ }
+ else if (main->program.parameters.array[controller_parameter_uninterruptible_e].result & f_console_result_found_e) {
+ main->setting.flag &= ~controller_main_flag_interruptible_e;
+ }
}
#endif // _di_controller_main_setting_load_
* @param main
* The program and settings data.
*
+ * Must not be NULL.
+ *
* This alters setting.state.status:
* F_okay on success.
*
* - error: Check if status is "error".
* - fine: Check if status is "fine".
* - help: Print help.
+ * - interruptible: The process is interruptible.
* - pipe: Use the input pipe.
* - print_first: When set, print new line to message output on program begin after loading settings.
* - print_last: When set, print new line to message output on program end.
controller_main_flag_error_e = 0x2,
controller_main_flag_fine_e = 0x4,
controller_main_flag_help_e = 0x8,
- controller_main_flag_pipe_e = 0x10,
- controller_main_flag_print_first_e = 0x20,
- controller_main_flag_print_last_e = 0x40,
- controller_main_flag_version_e = 0x80,
- controller_main_flag_version_copyright_help_e = 0x89,
- controller_main_flag_warning_e = 0x100,
+ controller_main_flag_interruptible_e = 0x10,
+ controller_main_flag_pipe_e = 0x20,
+ controller_main_flag_print_first_e = 0x40,
+ controller_main_flag_print_last_e = 0x80,
+ controller_main_flag_version_e = 0x100,
+ controller_main_flag_version_copyright_help_e = 0x181,
+ controller_main_flag_warning_e = 0x200,
}; // enum
#endif // _di_controller_main_flag_e_
*/
#ifndef _di_controller_parameter_e_
enum {
- controller_parameter_controller_e = f_console_standard_parameter_last_e,
+ controller_parameter_cgroup_e = f_console_standard_parameter_last_e,
+ controller_parameter_daemon_e,
+ controller_parameter_interruptible_e,
+ controller_parameter_pid_e,
+ controller_parameter_settings_e,
+ controller_parameter_simulate_e,
+ controller_parameter_socket_e,
+ controller_parameter_uninterruptible_e,
+ controller_parameter_validate_e,
}; // enum
#define controller_console_parameter_t_initialize \
#ifndef _di_controller_f_a_
const f_string_t controller_f_a[] = {
+ "f_controller_path_canonical_relative",
"f_console_parameter_process",
"f_path_current",
+ "f_string_append_assure",
"f_string_dynamic_append",
"f_thread_create",
"fll_program_parameter_process_context_standard",
*/
#ifndef _di_controller_f_e_
enum {
+ controller_f_controller_path_canonical_relative_e,
controller_f_f_console_parameter_process_e,
controller_f_f_path_current_e,
+ controller_f_f_string_append_assure_e,
controller_f_f_string_dynamic_append_e,
controller_f_f_thread_create_e,
controller_f_fll_program_parameter_process_context_standard_e,
/**
* The program defaults.
+ *
+ * These are defines inside the programs utilizing this rather than in the library itself.
*/
#ifndef _di_controller_default_s_
#define CONTROLLER_default_path_pid_s_length 5
#endif // defined(_override_controller_path_pid_) && defined(_override_controller_path_pid_length_)
- // The init pid path is a system-specific path and needs to be more easily controlled at compile time.
- #if defined(_override_controller_path_pid_init_) && defined(_override_controller_path_pid_init_length_)
- #define CONTROLLER_default_path_pid_init_s _override_controller_path_pid_init_
- #define CONTROLLER_default_path_pid_init_s_length _override_controller_path_pid_init_length_
- #else
- #define CONTROLLER_default_path_pid_init_s "/var/run/controller"
- #define CONTROLLER_default_path_pid_init_s_length 19
- #endif // defined(_override_controller_path_pid_init_) && defined(_override_controller_path_pid_init_length_)
-
// The pid prefix is a system-specific path part and needs to be more easily controlled at compile time.
#if defined(_override_controller_path_pid_prefix_) && defined(_override_controller_path_pid_prefix_length_)
#define CONTROLLER_default_path_pid_prefix_s _override_controller_path_pid_prefix_
#define CONTROLLER_default_path_settings_s_length 2
#endif // defined(_override_controller_path_settings_) && defined(_override_controller_path_settings_length_)
- // The init settings path is a system-specific path part and needs to be more easily controlled at compile time.
- #if defined(_override_controller_path_settings_init_) && defined(_override_controller_path_settings_init_length_)
- #define CONTROLLER_default_path_settings_init_s _override_controller_path_settings_init_
- #define CONTROLLER_default_path_settings_init_s_length _override_controller_path_settings_init_length_
- #else
- #define CONTROLLER_default_path_settings_init_s "/etc/controller"
- #define CONTROLLER_default_path_settings_init_s_length 15
- #endif // defined(_override_controller_path_settings_init_) && defined(_override_controller_path_settings_init_length_)
-
// The socket path is a system-specific path and needs to be more easily controlled at compile time.
#if defined(_override_controller_path_socket_) && defined(_override_controller_path_socket_length_)
#define CONTROLLER_default_path_socket_s _override_controller_path_socket_
#define CONTROLLER_default_path_socket_s_length 5
#endif // defined(_override_controller_path_socket_) && defined(_override_controller_path_socket_length_)
- // The socket path is a system-specific path and needs to be more easily controlled at compile time.
- #if defined(_override_controller_path_socket_init_) && defined(_override_controller_path_socket_init_length_)
- #define CONTROLLER_default_path_socket_init_s _override_controller_path_socket_init_
- #define CONTROLLER_default_path_socket_init_s_length _override_controller_path_socket_init_length_
- #else
- #define CONTROLLER_default_path_socket_init_s "/var/run/controller"
- #define CONTROLLER_default_path_socket_init_s_length 19
- #endif // defined(_override_controller_path_socket_init_) && defined(_override_controller_path_socket_init_length_)
-
// The socket prefix path is a system-specific path part and needs to be more easily controlled at compile time.
#if defined(_override_controller_path_socket_prefix_) && defined(_override_controller_path_socket_prefix_length_)
#define CONTROLLER_default_path_socket_prefix_s _override_controller_path_socket_prefix_
extern const f_string_static_t controller_default_engine_s;
extern const f_string_static_t controller_default_path_pid_s;
- extern const f_string_static_t controller_default_path_pid_init_s;
extern const f_string_static_t controller_default_path_pid_prefix_s;
extern const f_string_static_t controller_default_path_pid_suffix_s;
extern const f_string_static_t controller_default_path_settings_s;
- extern const f_string_static_t controller_default_path_settings_init_s;
extern const f_string_static_t controller_default_path_socket_s;
- extern const f_string_static_t controller_default_path_socket_init_s;
extern const f_string_static_t controller_default_path_socket_prefix_s;
extern const f_string_static_t controller_default_path_socket_suffix_s;
#endif // _di_controller_default_s_
* Delete the Controller process data.
*
* @param process
- * The controller process data.
+ * A pointer to the current process settings.
+ *
+ * Must not be NULL.
*
* @return
* F_okay on success.
*/
#ifndef _di_controller_rule_rerun_item_t_
typedef struct {
- bool reset;
+ uint8_t reset;
f_number_unsigned_t count;
f_number_unsigned_t delay;
extern "C" {
#endif
-#ifndef _di_controller_thread_delete_simple_
- void controller_thread_delete_simple(controller_thread_t * const thread) {
+#ifndef _di_controller_thread_delete_
+ void controller_thread_delete(controller_thread_t * const thread) {
+
+ if (!thread) return;
controller_lock_delete(&thread->lock);
controller_process_delete(&thread->process);
controller_cache_delete(&thread->cache);
}
-#endif // _di_controller_thread_delete_simple_
+#endif // _di_controller_thread_delete_
#ifdef __cplusplus
} // extern "C"
* 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.
+ * lock: A r/w lock for operating on this structure.
* process: All Rule Process thread data.
- * cache: A cache used by the main entry/rule processing thread for synchronous operations.
+ * cache: A cache used by the main entry/rule processing thread for synchronous operations.
*/
#ifndef _di_controller_thread_t_
typedef struct {
* @param thread
* The thread to deallocate.
*
+ * Must not be NULL.
+ *
* @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);
-#endif // _di_controller_thread_delete_simple_
+#ifndef _di_controller_thread_delete_
+ extern void controller_thread_delete(controller_thread_t * const thread);
+#endif // _di_controller_thread_delete_
#ifdef __cplusplus
} // extern "C"
// FLL-1 includes.
#include <fll/level_1/conversion.h>
+#include <fll/level_1/path.h>
#include <fll/level_1/print.h>
// FLL-2 includes.
#include <program/controller/main/common/type/thread.h>
#include <program/controller/main/common/type.h>
#include <program/controller/main/common.h>
+#include <program/controller/main/path.h>
#include <program/controller/main/print/data.h>
#include <program/controller/main/print/debug.h>
#include <program/controller/main/print/error.h>
+#include <program/controller/main/print/lock.h>
#include <program/controller/main/print/message.h>
#include <program/controller/main/print/verbose.h>
#include <program/controller/main/print/warning.h>
--- /dev/null
+#include "controller.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_controller_path_canonical_relative_
+ void controller_path_canonical_relative(controller_main_t * const main, const f_string_static_t current, const f_string_static_t source, f_string_dynamic_t * const destination) {
+
+ if (!main || !destination) return;
+
+ main->setting.state.status = fl_path_canonical(source, destination);
+ if (F_status_is_error(main->setting.state.status)) return;
+
+ if (destination->used >= current.used) {
+ const f_range_t range = macro_f_range_t_initialize_2(current.used);
+
+ if (f_compare_dynamic_partial_string(destination->string, current, destination->used, range) == F_equal_to) {
+ f_number_unsigned_t length = destination->used - current.used;
+
+ if (length) {
+ memmove(destination->string, destination->string + current.used + 1, sizeof(f_char_t) * (--length));
+
+ destination->string[length] = 0;
+ destination->used = length;
+ }
+ else {
+ destination->used = 0;
+ }
+ }
+ }
+
+ main->setting.state.status = F_okay;
+ }
+#endif // _di_controller_path_canonical_relative_
+
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Provides path functionality.
+ *
+ * This is auto-included and should not need to be explicitly included.
+ */
+#ifndef _controller_main_path_h
+#define _controller_main_path_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Determine a canonical path and then, if it is relative to the current working directory, make it a relative path.
+ *
+ * For example, given the paths "../hello/world/" and "../controller/files/" with a current working directory of "/tmp/controller", then a canonical path for these might look like:
+ * - "/tmp/hello/world/"
+ * - "/tmp/controller/files/"
+ *
+ * This function would instead result in the following:
+ * - "/tmp/hello/world/"
+ * - "files/"
+ * @param main
+ * The program and settings data.
+ *
+ * Must not be NULL.
+ *
+ * This alters setting.state.status:
+ * F_okay on success.
+ *
+ * Errors (with error bit) from: fl_path_canonical().
+ * @param current
+ * The current path, such as process.path_current.
+ * @param source
+ * The source path to determine the relative canonical from.
+ * @param destination
+ * The resulting relative canonical path.
+ * The destination will be completely replaced on success.
+ *
+ * @see fl_path_canonical()
+ *
+ * @see memmove()
+ */
+#ifndef _di_controller_path_canonical_relative_
+ extern void controller_path_canonical_relative(controller_main_t * const main, const f_string_static_t current, const f_string_static_t source, f_string_dynamic_t * const destination);
+#endif // _di_controller_path_canonical_relative_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_main_path_h
extern "C" {
#endif
+#ifndef _di_controller_main_print_debug_directory_path_empty_
+ f_status_t controller_main_print_debug_directory_path_empty(fl_print_t * const print, const f_string_static_t symbol, const f_string_static_t name) {
+
+ if (!print || !print->custom) return F_status_set_error(F_output_not);
+ if (print->verbosity < f_console_verbosity_debug_e) return F_output_not;
+
+ controller_main_t * const main = (controller_main_t *) print->custom;
+
+ controller_lock_print(print->to, 0);
+
+ fl_print_format("%r%[%QThe parameter '%]", print->to, f_string_eol_s, print->context, print->prefix, print->context);
+ fl_print_format(f_string_format_rr_single_s.string, print->to, print->set->notable, symbol, name, print->set->notable);
+ fl_print_format("%[' must be a file directory path but instead is an empty string, falling back to the default.%]%r", print->to, print->context, print->context, f_string_eol_s);
+
+ controller_unlock_print_flush(print->to, 0);
+
+ return F_okay;
+ }
+#endif // _di_controller_main_print_debug_directory_path_empty_
+
#ifdef __cplusplus
} // extern "C"
#endif
extern "C" {
#endif
+/**
+ * Print a debug message about the directory path string being empty.
+ *
+ * @param print
+ * The output structure to print to.
+ *
+ * Must not be NULL.
+ *
+ * This does not alter print.custom.setting.state.status.
+ * @param symbol
+ * The symbol string prepended to the parameter.
+ * This locks, uses, and unlocks the file stream.
+ * This is usually f_console_symbol_long_normal_s.
+ * @param name
+ * The parameter name.
+ *
+ * @return
+ * F_okay on success.
+ * F_output_not on success, but no printing is performed.
+ *
+ * F_output_not (with error bit) if setting is NULL.
+ *
+ * @see fll_error_print()
+ */
+#ifndef _di_controller_main_print_debug_directory_path_empty_
+ extern f_status_t controller_main_print_debug_directory_path_empty(fl_print_t * const print, const f_string_static_t symbol, const f_string_static_t name);
+#endif // _di_controller_main_print_debug_directory_path_empty_
+
#ifdef __cplusplus
} // extern "C"
#endif
}
#endif // _di_controller_main_print_error_
+#ifndef _di_controller_main_print_error_file_
+ f_status_t controller_main_print_error_file(fl_print_t * const print, const f_string_t function, const f_string_static_t name, const f_string_static_t operation, const uint8_t type) {
+
+ if (!print || !print->custom) return F_status_set_error(F_output_not);
+ if (print->verbosity == f_console_verbosity_quiet_e) return F_output_not;
+
+ controller_main_t * const main = (controller_main_t *) print->custom;
+
+ fll_error_file_print(print, F_status_set_fine(main->setting.state.status), function, fll_error_file_flag_fallback_e, name, operation, type);
+
+ return F_okay;
+ }
+#endif // _di_controller_main_print_error_file_
+
#ifdef __cplusplus
} // extern "C"
#endif
* @param print
* The output structure to print to.
*
+ * Must not be NULL.
+ *
* This does not alter print.custom.setting.state.status.
* @param function
* The name of the function associated with the error.
extern f_status_t controller_main_print_error(fl_print_t * const print, const f_string_t function);
#endif // _di_controller_main_print_error_
+/**
+ * Print file related error or warning messages.
+ *
+ * @param print
+ * The output structure to print to.
+ *
+ * Must not be NULL.
+ *
+ * The print.custom is expected to be of type fss_read_main_t.
+ *
+ * This does not alter print.custom.setting.state.status.
+ * @param function
+ * The name of the function where the error happened.
+ * Set to 0 to disable.
+ * @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.
+ *
+ * @return
+ * F_okay on success.
+ * F_output_not on success, but no printing is performed.
+ *
+ * F_output_not (with error bit) if a parameter is NULL.
+ *
+ * @see fll_error_file_print()
+ */
+#ifndef _di_controller_main_print_error_file_
+ extern f_status_t controller_main_print_error_file(fl_print_t * const print, const f_string_t function, const f_string_static_t name, const f_string_static_t operation, const uint8_t type);
+#endif // _di_controller_main_print_error_file_
+
#ifdef __cplusplus
} // extern "C"
#endif
--- /dev/null
+#include "../controller.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_controller_lock_print_error_critical_
+ void controller_lock_print_error_critical(fl_print_t * const print, const f_status_t status, const uint8_t is_read, controller_thread_t *thread) {
+
+ // A signal is not an error.
+ if (status == F_interrupt) return;
+
+ if (print->verbosity != f_console_verbosity_quiet_e) {
+ controller_lock_print(print->to, thread);
+
+ fl_print_format("%r%[%QThe pid file '%]", print->to, f_string_eol_s, print->context, print->prefix, print->context);
+ fl_print_format("%['Critical failure while attempting to establish '%]", print->to, print->context, print->context);
+ fl_print_format("%[%r lock%]", print->to, print->notable, is_read ? f_file_operation_read_s : f_file_operation_write_s, print->notable);
+
+ if (status != F_failure) {
+ fl_print_format(" %['due to%] ", print->to, print->context, print->context);
+
+ if (status == F_parameter) {
+ fl_print_format("%[Invalid Parameter%]", print->to, print->notable, print->notable);
+ }
+ else if (status == F_deadlock) {
+ fl_print_format("%[Deadlock%]", print->to, print->notable, print->notable);
+ }
+ else if (status == F_resource_not) {
+ fl_print_format("%[Too Many Locks%]", print->to, print->notable, print->notable);
+ }
+ else {
+ fl_print_format("%[Unknown Error%]", print->to, print->notable, print->notable);
+ }
+ }
+
+ fl_print_format(f_string_format_sentence_end_quote_s.string, print->to, print->context, print->context, f_string_eol_s);
+
+ controller_unlock_print_flush(print->to, thread);
+ }
+ }
+#endif // _di_controller_lock_print_error_critical_
+
+#ifndef _di_controller_lock_print_
+ void controller_lock_print(const f_file_t to, controller_thread_t * const thread) {
+
+ if (thread) {
+ f_thread_mutex_lock(&thread->lock.print);
+ }
+
+ f_file_stream_lock(to);
+ }
+#endif // _di_controller_lock_print_
+
+#ifndef _di_controller_unlock_print_flush_
+ void controller_unlock_print_flush(const f_file_t to, controller_thread_t * const thread) {
+
+ f_file_stream_flush(to);
+ f_file_stream_unlock(to);
+
+ if (thread) {
+ f_thread_mutex_unlock(&thread->lock.print);
+ }
+ }
+#endif // _di_controller_unlock_print_flush_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Provides the print lock functionality.
+ *
+ * This is auto-included and should not need to be explicitly included.
+ */
+#ifndef _controller_main_print_lock_h
+#define _controller_main_print_lock_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Print a r/w lock related error message, locking the print mutex during the print.
+ *
+ * This will ignore F_interrupt and not print any messages, if passed.
+ *
+ * @param print
+ * The output structure to print to.
+ *
+ * Must not be NULL.
+ *
+ * This does not alter print.custom.setting.state.status.
+ * @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 is_read
+ * If TRUE, then this is for a read lock.
+ * If FALSE, then this is for a write lock.
+ * @param thread
+ * The thread data.
+ */
+#ifndef _di_controller_lock_print_error_critical_
+ extern void controller_lock_print_error_critical(fl_print_t * const print, const f_status_t status, const uint8_t is_read, controller_thread_t *thread);
+#endif // _di_controller_lock_print_error_critical_
+
+/**
+ * Lock the mutex and the stream.
+ *
+ * This is implemented as a compliment to controller_unlock_print_flush() for consistency reasons.
+ *
+ * @param to
+ * The file stream to lock.
+ * @param thread
+ * (optonal) The thread containing the print mutex to lock.
+ * Set to NULL to not use.
+ *
+ * @see f_file_stream_lock()
+ * @see f_thread_mutex_unlock()
+ */
+#ifndef _di_controller_lock_print_
+ extern void controller_lock_print(const f_file_t to, controller_thread_t * const thread);
+#endif // _di_controller_lock_print_
+
+/**
+ * Flush the stream buffer and then unlock the mutex.
+ *
+ * This unlocks both the stream and the mutex locks.
+ *
+ * Weird behavior was observed when piping data from this program.
+ * The behavior appears related to how this handles locks in addition to the file streams own locking mechanisms.
+ *
+ * As a work-around, this performs a flush immediately before unlocking the print mutex.
+ *
+ * @param to
+ * The file stream to unlock and flush.
+ * @param thread
+ * (optonal) The thread containing the print mutex to unlock.
+ * Set to NULL to not use.
+ *
+ * @see f_file_stream_unlock()
+ *
+ * @see f_thread_mutex_unlock()
+ */
+#ifndef _di_controller_unlock_print_flush_
+ void controller_unlock_print_flush(const f_file_t to, controller_thread_t * const thread);
+#endif // _di_controller_unlock_print_flush_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_main_print_lock_h
}
#endif // _di_controller_main_print_message_help_
-
#ifdef __cplusplus
} // extern "C"
#endif
* @param main
* The program and settings data.
*
+ * Must not be NULL.
+ *
* Must be of type controller_main_t.
*
* @return