From 1c0c1913def6057649ea782715876465abfa64b3 Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Sun, 16 Nov 2025 18:16:18 -0600 Subject: [PATCH] Progress: Begin implementing controlfile and initfile support. The specifications are now implemented. Provide examples of the `controlfile` and the `initfile`. Comments some TODO's that I am thinking about and will set aside for future consideration. These TODO's will be removed once I wrap up the `controlfile` support regardless of whether or not I implement the TODOs. The `controller` and `init` programs have the basic file support setup, but no function to actually process these are implemented yet. My goal is to pre-process these files and then pass them along to the normal load functions. Ideally, the file should need only be loaded in memory once. I broke out some of the `controller_process()` functionality into another functions `controller_process_prepare()` and `controller_process_run()` for organizational purposes. There are potentially some stale TODO/`@todo` comments that will be addressed and removed as I complete this functionality. --- data/build/defines | 3 + data/build/settings | 1 + data/build/settings.controller | 1 + data/build/settings.init | 1 + .../controller/example/controlfile/controlfile | 64 +++++ data/data/controller/example/controlfile/initfile | 259 +++++++++++++++++++++ documents/controlfile.txt | 24 ++ documents/initfile.txt | 16 ++ sources/c/program/controller/controller/string.c | 4 + sources/c/program/controller/controller/string.h | 9 + sources/c/program/controller/init/string.c | 4 + sources/c/program/controller/init/string.h | 9 + sources/c/program/controller/main/common/define.h | 14 +- sources/c/program/controller/main/common/string.c | 6 + sources/c/program/controller/main/common/string.h | 21 ++ sources/c/program/controller/main/entry.c | 1 + sources/c/program/controller/main/process.c | 140 +++++++---- sources/c/program/controller/main/process.h | 62 ++++- specifications/controlfile.txt | 38 +++ specifications/initfile.txt | 17 ++ 20 files changed, 637 insertions(+), 57 deletions(-) create mode 100644 data/data/controller/example/controlfile/controlfile create mode 100644 data/data/controller/example/controlfile/initfile create mode 100644 documents/controlfile.txt create mode 100644 documents/initfile.txt create mode 100644 specifications/controlfile.txt create mode 100644 specifications/initfile.txt diff --git a/data/build/defines b/data/build/defines index f282d0f..7fccb9f 100644 --- a/data/build/defines +++ b/data/build/defines @@ -5,6 +5,9 @@ _di_thread_support_ Disables thread support. _libcap_legacy_only_ Disable functionality provided by later versions of libcap (2.43 and later). +_support_controller_controlfile_ Enable support for the controlfile by the controller program and library. +_support_controller_initfile_ Enable support for the initfile by the init program (requires _support_controller_controlfile_). + _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. diff --git a/data/build/settings b/data/build/settings index dd8273d..1ceef88 100644 --- a/data/build/settings +++ b/data/build/settings @@ -127,6 +127,7 @@ environment LANG LC_ALL LC_COLLATE LC_CTYPE LC_FASTMSG LC_MESSAGES LC_MONETARY L #defines -D_di_libcap_ defines -D_libcap_legacy_only_ +defines -D_support_controller_controlfile_ defines-android -D_di_f_thread_attribute_affinity_get_ -D_di_f_thread_attribute_affinity_set_ -D_di_f_thread_attribute_concurrency_get_ -D_di_f_thread_attribute_concurrency_set_ -D_di_f_thread_attribute_default_get_ -D_di_f_thread_attribute_default_set_ -D_di_f_thread_cancel_ -D_di_f_thread_cancel_state_set_ -D_di_f_thread_cancel_test_ -D_di_f_thread_join_try_ -D_di_f_thread_join_timed_ -D_pthread_mutex_prioceiling_unsupported_ -D_di_f_thread_semaphore_file_close_ -D_di_f_thread_semaphore_file_open_ -D_di_f_thread_semaphore_file_delete_ -D_di_f_thread_cancel_type_set_ defines-debug -D_en_f_status_debug_ F_status_debug_source_d diff --git a/data/build/settings.controller b/data/build/settings.controller index f6f6156..674be42 100644 --- a/data/build/settings.controller +++ b/data/build/settings.controller @@ -89,6 +89,7 @@ environment LANG LC_ALL LC_COLLATE LC_CTYPE LC_FASTMSG LC_MESSAGES LC_MONETARY L #defines -D_di_libcap_ defines -D_libcap_legacy_only_ +defines -D_support_controller_controlfile_ defines-android -D_di_f_thread_attribute_affinity_get_ -D_di_f_thread_attribute_affinity_set_ -D_di_f_thread_attribute_concurrency_get_ -D_di_f_thread_attribute_concurrency_set_ -D_di_f_thread_attribute_default_get_ -D_di_f_thread_attribute_default_set_ -D_di_f_thread_cancel_ -D_di_f_thread_cancel_state_set_ -D_di_f_thread_cancel_test_ -D_di_f_thread_join_try_ -D_di_f_thread_join_timed_ -D_pthread_mutex_prioceiling_unsupported_ -D_di_f_thread_semaphore_file_close_ -D_di_f_thread_semaphore_file_open_ -D_di_f_thread_semaphore_file_delete_ -D_di_f_thread_cancel_type_set_ defines-debug -D_en_f_status_debug_ defines-thread -D_pthread_attr_unsupported_ -D_pthread_sigqueue_unsupported_ diff --git a/data/build/settings.init b/data/build/settings.init index 2f84a39..78f273b 100644 --- a/data/build/settings.init +++ b/data/build/settings.init @@ -89,6 +89,7 @@ environment LANG LC_ALL LC_COLLATE LC_CTYPE LC_FASTMSG LC_MESSAGES LC_MONETARY L #defines -D_di_libcap_ defines -D_libcap_legacy_only_ +defines -D_support_controller_controlfile_ -D_support_controller_initfile_ defines-android -D_di_f_thread_attribute_affinity_get_ -D_di_f_thread_attribute_affinity_set_ -D_di_f_thread_attribute_concurrency_get_ -D_di_f_thread_attribute_concurrency_set_ -D_di_f_thread_attribute_default_get_ -D_di_f_thread_attribute_default_set_ -D_di_f_thread_cancel_ -D_di_f_thread_cancel_state_set_ -D_di_f_thread_cancel_test_ -D_di_f_thread_join_try_ -D_di_f_thread_join_timed_ -D_pthread_mutex_prioceiling_unsupported_ -D_di_f_thread_semaphore_file_close_ -D_di_f_thread_semaphore_file_open_ -D_di_f_thread_semaphore_file_delete_ -D_di_f_thread_cancel_type_set_ defines-debug -D_en_f_status_debug_ defines-thread -D_pthread_attr_unsupported_ -D_pthread_sigqueue_unsupported_ diff --git a/data/data/controller/example/controlfile/controlfile b/data/data/controller/example/controlfile/controlfile new file mode 100644 index 0000000..bdec963 --- /dev/null +++ b/data/data/controller/example/controlfile/controlfile @@ -0,0 +1,64 @@ +# fss-0005 fss-000d iki-0000 +# +# Example controlfile based on the example files: +# - miscellaneous/entries/serial.entry. +# - miscellaneous/exits/serial.exit. +# - miscellaneous/rules/serial/s_1.rule +# - miscellaneous/rules/serial/s_2.rule +# - miscellaneous/rules/serial/s_3.rule +# - miscellaneous/rules/serial/s_4.rule +# - miscellaneous/rules/serial/s_5.rule +# - miscellaneous/rules/serial/s_6.rule +# + +entry_main: + consider serial s_1 + consider serial s_2 + consider serial s_3 + consider serial s_4 + consider serial s_5 + + start serial s_6 + + ready + +exit_main: + consider serial s_1 + consider serial s_2 + consider serial s_3 + consider serial s_4 + consider serial s_5 + consider serial s_6 + + stop serial s_1 + + ready + +rule_serial_s_1_settings: + name "Serial 1" + on stop need serial s_2 + +rule_serial_s_1_script: + start { + main() { + local IFS=$' \t\n' # Prevent IFS exploits by overriding with a local scope. + + echo "Serial 1: sleeping $(date -u)" + sleep 1 + echo "Serial 1: slept $(date -u)" + \} + + main ${*} + } + + stop { + main() { + local IFS=$' \t\n' # Prevent IFS exploits by overriding with a local scope. + + echo "Serial 1: stopping, sleeping $(date -u)" + sleep 1 + echo "Serial 1: stopping, slept $(date -u)" + \} + + main ${*} + } diff --git a/data/data/controller/example/controlfile/initfile b/data/data/controller/example/controlfile/initfile new file mode 100644 index 0000000..465d429 --- /dev/null +++ b/data/data/controller/example/controlfile/initfile @@ -0,0 +1,259 @@ +# fss-0005 fss-000d iki-0000 +# +# Example initfile based on the init/entries/default.entry and many of its related files. +# + +entry_settings: + pid ready + show init + + control init.socket + control_user 0 + control_group 0 + control_mode ug+rwx,o-rwx + +entry_main: + timeout start 7 + timeout stop 7 + timeout kill 3 + + failsafe maintenance + + item boot + item console + +entry_boot: + start boot root require + start boot proc asynchronous require + start boot devices asynchronous require + start boot file_system asynchronous + start boot modules wait + + ready + +entry_console: + start service mouse asynchronous + + start terminal two asynchronous + start terminal three asynchronous + start terminal four asynchronous + start terminal one require wait + +entry_maintenance: + # TODO: Support IKI variables for certain env data, such as an architecture path (thus '/bin[environment:"architecture_path"]/bash'). with some compilation built ins, or maybe have settings support calling programs to populate variables, like '/bin[variable:"architecture_path"]/bash'. + # TODO: There could even be settings, entries, and exits to support for calling and processing custom, named, functions built into the source code. + execute /bin/bash --login + +rule_boot_devices_settings: + name "Setup /dev file system" + + on start need boot root + +rule_boot_devices_script: + start { + main() { + local IFS=$' \t\n' # Prevent IFS exploits by overriding with a local scope. + + if [[ ! -d /dev/pts ]] ; then + mkdir /dev/pts + fi + + if [[ ! -d /dev/shm ]] ; then + mkdir /dev/shm + fi + + return 0 + \} + + main ${*} + } + +rule_boot_devices_command: + start mount /dev/pts + stop umount -l /dev/pts + +rule_boot_devices_command: + start mount /dev/shm + stop umount -l /dev/shm + +rule_boot_file_system_settings: + name "Setup Filesystem" + + on start need boot root + on start need boot proc + on start need boot devices + + on stop need boot proc + on stop need boot devices + +rule_boot_file_system_command: + start mount -n -a -O no_netdev + stop umount -n -arf -O no_netdev + +rule_boot_file_system_command: + start swapon -a + stop swapoff -a + +rule_boot_file_system_script: + start { + main() { + local IFS=$' \t\n' # Prevent IFS exploits by overriding with a local scope. + + if [[ ! -d /var/run/init ]] ; then + mkdir /var/run/init + fi + \} + + main ${*} + } + +rule_boot_modules_settings: + name "Setup Kernel Modules" + + on start need boot root + on start need boot proc + on start want boot filesystem + +rule_boot_modules_script: + start { + main() { + local IFS=$' \t\n' # Prevent IFS exploits by overriding with a local scope. + + if [[ ! -f /proc/modules ]] ; then + exit 0 + fi + + if [[ -d /modules ]] ; then + if [[ ! -e /modules/$(uname -r)/modules.dep ]] ; then + depmod + else + depmod -A + fi + fi + + return 0 + \} + + main ${*} + } + +rule_boot_proc_settings: + name "Setup /proc Filesystem" + + on start need boot root + +rule_boot_proc_command: + start mount /proc + +rule_boot_proc_script: + start { + main() { + local IFS=$' \t\n' # Prevent IFS exploits by overriding with a local scope. + + if [[ -d /proc/bus/usb ]] ; then + mount /proc/bus/usb + fi + + return 0 + \} + + main ${*} + } + + stop { + main() { + local IFS=$' \t\n' # Prevent IFS exploits by overriding with a local scope. + + if [[ -d /proc/bus/usb ]] ; then + umount -l /proc/bus/usb + fi + + return 0 + \} + + main ${*} + } + +rule_boot_root_settings: + name "Setup Root Filesystem" + +rule_boot_root_command: + start mount -o remount,rw / + +rule_boot_root_script: + start { + main() { + local IFS=$' \t\n' # Prevent IFS exploits by overriding with a local scope. + local i= + + for i in /dev /dev/pts /dev/shm /firmware /mnt /modules /proc /sys /tmp /var /var/log /var/run /var/tmp ; do + if [[ ! -d ${i} ]] ; then + mkdir ${i} + fi + done + + return 0 + \} + + main ${*} + } + +rule_service_mouse_settings: + name "Console Mouse" + capability all= + nice 15 + +rule_service_mouse_script: + start { + main() { + local IFS=$' \t\n' # Prevent IFS exploits by overriding with a local scope. + + # This works if gpm service is run as root, but if not then this should be in a separate rule file with appropriate access to write to /var/run (don't forget to chown!). + if [[ ! -d /var/run/mouse/ && -d /var/run ]] ; then + mkdir /var/run/mouse/ + fi + \} + + main ${*} + } + +rule_service_mouse_service: + pid_file /var/run/mouse/mouse.pid + + start gpm -m variable:"device" -t variable:"protocol" variable:"options" + +rule_terminal_one_settings: + name "System Terminal 1" + +rule_terminal_one_command: + start agetty -8 -i -J - linux + + rerun start success delay 1000 reset + rerun start failure delay 5000 + +rule_terminal_two_settings: + name "System Terminal 2" + +rule_terminal_two_command: + start agetty -8 tty2 linux + + rerun start success delay 1000 reset + rerun start failure delay 5000 max 100 + +rule_terminal_three_settings: + name "System Terminal 3" + +rule_terminal_three_command: + start agetty -8 tty3 linux + + rerun start success delay 1000 reset + rerun start failure delay 5000 max 100 + +rule_terminal_four_settings: + name "System Terminal 4" + +rule_terminal_four_command: + start agetty -8 tty4 linux + + rerun start success delay 1000 reset + rerun start failure delay 5000 max 100 diff --git a/documents/controlfile.txt b/documents/controlfile.txt new file mode 100644 index 0000000..a62a6dd --- /dev/null +++ b/documents/controlfile.txt @@ -0,0 +1,24 @@ +# fss-0002 iki-0000 +# +# license: open-standard-license-1.0-or-later +# version 2025/11/17 +# +# This file (assumed to be named controlfile.txt) can be more easily read using the following iki_read commands: +# iki_read controlfile.txt +Q -w -WW code '"' '"' file '"' '"' +# +# To read the "Control File Documentation" section of this file, use this command sequence: +# fss_basic_list_read controlfile.txt +Q -cn "Control File Documentation" | iki_read +Q -w -WW code '"' '"' file '"' '"' +# + +Control File Documentation: + + A control file is intended to be used by controller programs similar to how the code:"fakefile" is used by the bold:"Featureless Make" program. + + A control file consists of the file:"entry.txt", file:"exit.txt", and file:"rule.txt" all merged into a single file. + The goal of of a control file is to collapse the directory hierarchy structure into a single file. + This imposes no new Objects or other structures. + + Any modifications, or deviations, from this standard that add additional things beyond the entry, exit, and rule are encouraged to follow the naming prefix pattern. + The naming pattern is the simple standard name, like code:"entry", code:"exit", or code:"rule", followed by an underscore as a prefix. + Then all Object names would then have that prefix. + For example if there were a specification called file:"system" with an Object called code:"power_on" at the top level, then the control file representation would be code:"system_power_on". diff --git a/documents/initfile.txt b/documents/initfile.txt new file mode 100644 index 0000000..816eef5 --- /dev/null +++ b/documents/initfile.txt @@ -0,0 +1,16 @@ +# fss-0002 iki-0000 +# +# license: open-standard-license-1.0-or-later +# version 2025/11/17 +# +# This file (assumed to be named initfile.txt) can be more easily read using the following iki_read commands: +# iki_read initfile.txt +Q -w -W file '"' '"' +# +# To read the "Init File Documentation" section of this file, use this command sequence: +# fss_basic_list_read initfile.txt +Q -cn "Init File Documentation" | iki_read +Q -w -W file '"' '"' +# + +Init File Documentation: + + An init file is the init program specific version of the file:"controlfile". + The init program should use an file:"initfile" instead of a file:"controlfile", if supported. diff --git a/sources/c/program/controller/controller/string.c b/sources/c/program/controller/controller/string.c index b14998d..6c76ad5 100644 --- a/sources/c/program/controller/controller/string.c +++ b/sources/c/program/controller/controller/string.c @@ -9,6 +9,10 @@ extern "C" { const f_string_static_t controller_program_name_long_s = macro_f_string_static_t_initialize_1(CONTROLLER_program_name_long_s, 0, CONTROLLER_program_name_long_s_length); #endif // _di_controller_program_name_s_ +#if !defined(_di_controller_controlfile_s_) && defined(_support_controller_controlfile_) + const f_string_static_t controller_controlfile_s = macro_f_string_static_t_initialize_1(CONTROLLER_controlfile_s, 0, CONTROLLER_controlfile_s_length); +#endif // !defined(_di_controller_controlfile_s_) && defined(_support_controller_controlfile_) + #ifndef _di_controller_default_s_ const f_string_static_t controller_default_engine_s = macro_f_string_static_t_initialize_1(CONTROLLER_default_engine_s, 0, CONTROLLER_default_engine_s_length); const f_string_static_t controller_default_path_pid_s = macro_f_string_static_t_initialize_1(CONTROLLER_default_path_pid_s, 0, CONTROLLER_default_path_pid_s_length); diff --git a/sources/c/program/controller/controller/string.h b/sources/c/program/controller/controller/string.h index 4870bc0..3c54dd5 100644 --- a/sources/c/program/controller/controller/string.h +++ b/sources/c/program/controller/controller/string.h @@ -28,6 +28,15 @@ extern "C" { #endif // _di_controller_program_name_s_ /** + * Controlfile strings. + */ +#if !defined(_di_controller_controlfile_s_) && defined(_support_controller_controlfile_) + #define CONTROLLER_controlfile_s "controlfile" + + #define CONTROLLER_controlfile_s_length 11 +#endif // !defined(_di_controller_controlfile_s_) && defined(_support_controller_controlfile_) + +/** * The program defaults. */ #ifndef _di_controller_default_s_ diff --git a/sources/c/program/controller/init/string.c b/sources/c/program/controller/init/string.c index c34bf3e..bdc0874 100644 --- a/sources/c/program/controller/init/string.c +++ b/sources/c/program/controller/init/string.c @@ -9,6 +9,10 @@ extern "C" { const f_string_static_t controller_program_name_long_s = macro_f_string_static_t_initialize_1(CONTROLLER_program_name_long_s, 0, CONTROLLER_program_name_long_s_length); #endif // _di_controller_program_name_s_ +#if !defined(_di_controller_controlfile_s_) && defined(_support_controller_controlfile_) + const f_string_static_t controller_controlfile_s = macro_f_string_static_t_initialize_1(CONTROLLER_controlfile_s, 0, CONTROLLER_controlfile_s_length); +#endif // !defined(_di_controller_controlfile_s_) && defined(_support_controller_controlfile_) + #ifndef _di_controller_default_s_ const f_string_static_t controller_default_engine_s = macro_f_string_static_t_initialize_1(CONTROLLER_default_engine_s, 0, CONTROLLER_default_engine_s_length); const f_string_static_t controller_default_path_pid_s = macro_f_string_static_t_initialize_1(CONTROLLER_init_default_path_pid_s, 0, CONTROLLER_init_default_path_pid_s_length); diff --git a/sources/c/program/controller/init/string.h b/sources/c/program/controller/init/string.h index 3e3aac5..eba5edb 100644 --- a/sources/c/program/controller/init/string.h +++ b/sources/c/program/controller/init/string.h @@ -28,6 +28,15 @@ extern "C" { #endif // _di_controller_program_name_s_ /** + * Controlfile strings. + */ +#if !defined(_di_controller_controlfile_s_) && defined(_support_controller_controlfile_) + #define CONTROLLER_controlfile_s "initfile" + + #define CONTROLLER_controlfile_s_length 8 +#endif // !defined(_di_controller_controlfile_s_) && defined(_support_controller_controlfile_) + +/** * The program defaults. */ #ifndef _di_controller_default_s_ diff --git a/sources/c/program/controller/main/common/define.h b/sources/c/program/controller/main/common/define.h index 01825f6..144aa79 100644 --- a/sources/c/program/controller/main/common/define.h +++ b/sources/c/program/controller/main/common/define.h @@ -87,6 +87,7 @@ extern "C" { * - fine: Check if status is "fine". * - help: Print help. * - interruptible: The process is interruptible. + * - loaded: Designate that the files are all loaded (generally only set when a controlfile exists and is loaded). * - pid: Designate that a custom PID is specified. * - pipe: Use the input pipe. * - simulate: Perform simulation of rules rather than execution. @@ -102,12 +103,13 @@ extern "C" { #define controller_main_flag_fine_d 0x8 #define controller_main_flag_help_d 0x10 #define controller_main_flag_interruptible_d 0x20 - #define controller_main_flag_pid_d 0x40 - #define controller_main_flag_pipe_d 0x80 - #define controller_main_flag_simulate_d 0x100 - #define controller_main_flag_validate_d 0x200 - #define controller_main_flag_version_d 0x400 - #define controller_main_flag_version_copyright_help_d 0x411 + #define controller_main_flag_loaded_d 0x40 + #define controller_main_flag_pid_d 0x80 + #define controller_main_flag_pipe_d 0x100 + #define controller_main_flag_simulate_d 0x200 + #define controller_main_flag_validate_d 0x400 + #define controller_main_flag_version_d 0x800 + #define controller_main_flag_version_copyright_help_d 0x811 #endif // _di_controller_main_flag_d_ /** diff --git a/sources/c/program/controller/main/common/string.c b/sources/c/program/controller/main/common/string.c index e7b9f95..fb1d83f 100644 --- a/sources/c/program/controller/main/common/string.c +++ b/sources/c/program/controller/main/common/string.c @@ -8,6 +8,12 @@ extern "C" { const f_string_static_t controller_program_version_s = macro_f_string_static_t_initialize_1(CONTROLLER_program_version_s, 0, CONTROLLER_program_version_s_length); #endif // _di_controller_program_version_s_ +#if !defined(_di_controller_controlfile_s_) && defined(_support_controller_controlfile_) + const f_string_static_t controller_prefix_entry_s = macro_f_string_static_t_initialize_1(CONTROLLER_prefix_entry_s, 0, CONTROLLER_prefix_entry_s_length); + const f_string_static_t controller_prefix_exit_s = macro_f_string_static_t_initialize_1(CONTROLLER_prefix_exit_s, 0, CONTROLLER_prefix_exit_s_length); + const f_string_static_t controller_prefix_rule_s = macro_f_string_static_t_initialize_1(CONTROLLER_prefix_rule_s, 0, CONTROLLER_prefix_rule_s_length); +#endif // !defined(_di_controller_controlfile_s_) && defined(_support_controller_controlfile_) + #ifndef _di_controller_parameter_s_ const f_string_static_t controller_short_cgroup_s = macro_f_string_static_t_initialize_1(CONTROLLER_short_cgroup_s, 0, CONTROLLER_short_cgroup_s_length); const f_string_static_t controller_short_daemon_s = macro_f_string_static_t_initialize_1(CONTROLLER_short_daemon_s, 0, CONTROLLER_short_daemon_s_length); diff --git a/sources/c/program/controller/main/common/string.h b/sources/c/program/controller/main/common/string.h index 413c7a9..dd34385 100644 --- a/sources/c/program/controller/main/common/string.h +++ b/sources/c/program/controller/main/common/string.h @@ -56,6 +56,27 @@ extern "C" { #endif // _di_controller_program_name_s_ /** + * Controlfile strings. + * + * The controller_controlfile_s implementation is defined within the individual programs. + */ +#if !defined(_di_controller_controlfile_s_) && defined(_support_controller_controlfile_) + #define CONTROLLER_prefix_entry_s "entry_" + #define CONTROLLER_prefix_exit_s "exit_" + #define CONTROLLER_prefix_rule_s "rule_" + + #define CONTROLLER_prefix_entry_s_length 6 + #define CONTROLLER_prefix_exit_s_length 5 + #define CONTROLLER_prefix_rule_s_length 5 + + extern const f_string_static_t controller_controlfile_s; + + extern const f_string_static_t controller_prefix_entry_s_length; + extern const f_string_static_t controller_prefix_exit_s_length; + extern const f_string_static_t controller_prefix_rule_s_length; +#endif // !defined(_di_controller_controlfile_s_) && defined(_support_controller_controlfile_) + +/** * The main program parameters. */ #ifndef _di_controller_parameter_s_ diff --git a/sources/c/program/controller/main/entry.c b/sources/c/program/controller/main/entry.c index 4573abc..851254f 100644 --- a/sources/c/program/controller/main/entry.c +++ b/sources/c/program/controller/main/entry.c @@ -72,6 +72,7 @@ extern "C" { main->thread.cache.action.name_action.used = 0; main->thread.cache.action.name_item.used = 0; + // @todo Check if controlfile, then load that using the prefix, otherwise, operate normally. The full controlfile will be loaded once. Maybe make the file load a callback? if (F_status_is_error_not(state.status)) { if (is_entry) { state.status = controller_file_load(main, F_true, controller_entries_s, main->process.name_entry, controller_entry_s); diff --git a/sources/c/program/controller/main/process.c b/sources/c/program/controller/main/process.c index 639fd5e..f2f2b6a 100644 --- a/sources/c/program/controller/main/process.c +++ b/sources/c/program/controller/main/process.c @@ -56,69 +56,25 @@ extern "C" { else { status = controller_thread_signal_create(main, &controller_thread_signal_normal); - if (F_status_is_error_not(status)) { - - // Start the clean up thread so that it can handle any zombie reaping. - if (!(main->setting.flag & controller_main_flag_validate_d) && main->process.mode == controller_process_mode_service_e) { - if (!main->thread.id_cleanup) { - status = f_thread_create(0, &main->thread.id_cleanup, &controller_thread_cleanup, (void *) main); - } - } - } - if (F_status_is_error(status)) { main->thread.id_signal = 0; - main->thread.id_cleanup = 0; controller_print_error_status(&main->program.error, F_status_debug_source_d, status); } else { - if (main->setting.flag & controller_main_flag_daemon_d) { - main->process.ready = controller_process_ready_done_e; - - if (f_file_exists(main->process.path_pid, F_true) == F_true) { - status = F_status_set_error(F_available_not); - main->process.ready = controller_process_ready_abort_e; - - controller_print_error_file_pid_exists(&main->program.error, &main->thread, main->process.path_pid); - } - } - else if (main->process.name_entry.used) { - status = f_thread_create(0, &main->thread.id_entry, &controller_thread_entry, (void *) main); - - if (F_status_is_error(status)) { - controller_print_error_status(&main->program.error, F_status_debug_source_d, status); - } - else { - if (main->thread.id_entry) { - controller_thread_join(&main->thread.id_entry); - } + #ifdef _support_controller_controlfile_ + // @todo load the controlfile/initfile and start the thread. controller_main_flag_loaded_d + #endif // _support_controller_controlfile_ - status = main->thread.status; - } + if (F_status_is_error_not(status)) { + status = controller_process_prepare(main); } } } // Only make the Rule and control threads available once any/all pre-processing is complete. if (F_status_is_error_not(status) && status != F_failure && status != F_child && controller_thread_enable_get(&main->thread) == controller_thread_enable_e) { - if (!(main->setting.flag & controller_main_flag_validate_d)) { - - // Wait for the Entry thread to complete before starting the Rule thread. - if (main->thread.id_rule) { - controller_thread_join(&main->thread.id_rule); - } - - if (controller_thread_enable_get(&main->thread) > controller_thread_enable_not_e && main->process.mode == controller_process_mode_service_e) { - status = f_thread_create(0, &main->thread.id_rule, &controller_thread_rule, (void *) main); - - if (F_status_is_error(status)) { - main->thread.id_rule = 0; - - controller_print_error_status(&main->program.error, F_status_debug_source_d, status); - } - } - } + status = controller_process_run(main); } if (status == F_child) { @@ -175,6 +131,90 @@ extern "C" { } #endif // _di_controller_process_ +#ifndef _di_controller_process_prepare_ + f_status_t controller_process_prepare(controller_t * const main) { + + if (!main) return F_status_set_error(F_parameter); + + f_status_t status = F_okay; + + // Start the clean up thread so that it can handle any zombie reaping. + if (!(main->setting.flag & controller_main_flag_validate_d) && main->process.mode == controller_process_mode_service_e) { + if (!main->thread.id_cleanup) { + status = f_thread_create(0, &main->thread.id_cleanup, &controller_thread_cleanup, (void *) main); + + if (F_status_is_error(status)) { + main->thread.id_cleanup = 0; + + controller_print_error_status(&main->program.error, F_status_debug_source_d, status); + } + } + } + + if (F_status_is_error_not(status)) { + if (main->setting.flag & controller_main_flag_daemon_d) { + status = F_okay; + main->process.ready = controller_process_ready_done_e; + + if (f_file_exists(main->process.path_pid, F_true) == F_true) { + status = F_status_set_error(F_available_not); + main->process.ready = controller_process_ready_abort_e; + + controller_print_error_file_pid_exists(&main->program.error, &main->thread, main->process.path_pid); + } + } + else if (main->process.name_entry.used) { + status = f_thread_create(0, &main->thread.id_entry, &controller_thread_entry, (void *) main); + + if (F_status_is_error(status)) { + controller_print_error_status(&main->program.error, F_status_debug_source_d, status); + } + else { + if (main->thread.id_entry) { + controller_thread_join(&main->thread.id_entry); + } + + status = main->thread.status; + } + } + } + + return status; + } +#endif // _di_controller_process_prepare_ + +#ifndef _di_controller_process_run_ + f_status_t controller_process_run(controller_t * const main) { + + if (!main) return F_status_set_error(F_parameter); + + f_status_t status = F_okay; + + if (!(main->setting.flag & controller_main_flag_validate_d)) { + + // Wait for the Entry thread to complete before starting the Rule thread. + if (main->thread.id_rule) { + controller_thread_join(&main->thread.id_rule); + } + + if (controller_thread_enable_get(&main->thread) > controller_thread_enable_not_e && main->process.mode == controller_process_mode_service_e) { + status = f_thread_create(0, &main->thread.id_rule, &controller_thread_rule, (void *) main); + + if (F_status_is_error(status)) { + main->thread.id_rule = 0; + + controller_print_error_status(&main->program.error, F_status_debug_source_d, status); + } + else { + status = F_okay; + } + } + } + + return status; + } +#endif // _di_controller_process_run_ + #ifdef __cplusplus } // extern "C" #endif diff --git a/sources/c/program/controller/main/process.h b/sources/c/program/controller/main/process.h index cc27edd..2f31053 100644 --- a/sources/c/program/controller/main/process.h +++ b/sources/c/program/controller/main/process.h @@ -33,7 +33,7 @@ extern "C" { * * Must not be NULL. * - * This alters main.setting.state.status: + * This does not alter main.setting.state.status. * * @return * F_child on child process exiting. @@ -43,11 +43,71 @@ extern "C" { * F_parameter (with error bit) if a parameter is invalid. * * F_failure (with error bit) on any other error. + * + * Errors (with error bit) from: controller_process_prepare() + * + * @see controller_process_prepare() */ #ifndef controller_process extern f_status_t controller_process(controller_t * const main); #endif // controller_process +/** + * Perform the normal process preparation operations. + * + * This prints on error. + * + * @param main + * The main program data and settings. + * + * Must not be NULL. + * + * This does not alter main.setting.state.status. + * + * @return + * F_okay on success. + * + * F_available_not (with error bit) if the path PID file already exists while operaeting as controller_main_flag_daemon_d. + * F_parameter (with error bit) if a parameter is invalid. + * + * The value of main->thread.status may be returned if the entry thread runs and completes. + * + * Errors (with error bit) from: f_thread_create() + * + * @see f_thread_create() + */ +#ifndef _di_controller_process_prepare_ + extern f_status_t controller_process_prepare(controller_t * const main); +#endif // _di_controller_process_prepare_ + +/** + * Perform the normal process run operations. + * + * This prints on error. + * + * @param main + * The main program data and settings. + * + * Must not be NULL. + * + * This does not alter main.setting.state.status. + * + * @return + * F_okay on success. + * + * F_available_not (with error bit) if the path PID file already exists while operaeting as controller_main_flag_daemon_d. + * F_parameter (with error bit) if a parameter is invalid. + * + * The value of main->thread.status may be returned if the entry thread runs and completes. + * + * Errors (with error bit) from: f_thread_create() + * + * @see f_thread_create() + */ +#ifndef _di_controller_process_run_ + extern f_status_t controller_process_run(controller_t * const main); +#endif // _di_controller_process_run_ + #ifdef __cplusplus } // extern "C" #endif diff --git a/specifications/controlfile.txt b/specifications/controlfile.txt new file mode 100644 index 0000000..ab904bd --- /dev/null +++ b/specifications/controlfile.txt @@ -0,0 +1,38 @@ +# fss-0002 iki-0000 +# +# license: open-standard-license-1.0-or-later +# version 2025/11/17 +# +# This file (assumed to be named controlfile.txt) can be more easily read using the following iki_read commands: +# iki_read controlfile.txt +Q -w -WW code '"' '"' file '"' '"' +# +# To read the "Controlfile Specification" section of this file, use this command sequence: +# fss_basic_list_read controlfile.txt +Q -cn "Controlfile Specification" | iki_read +Q -w -WW code '"' '"' file '"' '"' +# + +Controlfile Specification: + A control file follows the code:"FSS-0005 (Somewhat Basic List)" and the code:"FSS-000D (Basic Rule)" format with bold:"IKI-0000 (Unrestricted)" format. + + A control file name is expected to have the exact name of file:"controlfile". + The file:"controlfile" is all lower case and has no file extension. + + A control file consists of the file:"entry.txt", file:"exit.txt", and file:"rule.txt" all merged into a single file. + All of the specifications apply, except for the name of the Objects. + The names of the Objects are as follows. + + For file:"entry.txt": + - The code:"main" is now called code:"entry_main". + - The code:"settings" is now called code:"entry_settings". + + For file:"exit.txt": + - The code:"main" is now called code:"exit_main". + - The code:"settings" is now called code:"exit_settings". + + For file:"rule.txt": + - The code:"command" is now called code:"rule_command". + - The code:"script" is now called code:"rule_script". + - The code:"service" is now called code:"rule_service". + - The code:"settings" is now called code:"rule_settings". + - The code:"utility" is now called code:"rule_utility". + + Any additional specifications brought in are be expected to follow the same pattern for combining. diff --git a/specifications/initfile.txt b/specifications/initfile.txt new file mode 100644 index 0000000..00707ed --- /dev/null +++ b/specifications/initfile.txt @@ -0,0 +1,17 @@ +# fss-0002 iki-0000 +# +# license: open-standard-license-1.0-or-later +# version 2025/11/17 +# +# This file (assumed to be named initfile.txt) can be more easily read using the following iki_read commands: +# iki_read initfile.txt +Q -w -W file '"' '"' +# +# To read the "Init File Specification" section of this file, use this command sequence: +# fss_basic_list_read initfile.txt +Q -cn "Init File Specification" | iki_read +Q -w -W file '"' '"' +# + +Init File Specification: + An init file is identical to a control file in all but name. + + An Initfile file name is expected to have the exact name of file:"initfile". + The file:"initfile" is all lower case and has no file extension. -- 1.8.3.1