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.
_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.
#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
#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_
#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_
--- /dev/null
+# 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 ${*}
+ }
--- /dev/null
+# 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
--- /dev/null
+# 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".
--- /dev/null
+# 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.
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);
#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_
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);
#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_
* - 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.
#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_
/**
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);
#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_
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);
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) {
}
#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
*
* 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.
* 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
--- /dev/null
+# 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.
--- /dev/null
+# 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.