The standard shutdown/reboot/ctrl-alt-delete process actually operates via interrupts.
Make the init program interruptible by default and add notes in the help.
Add additional callbacks.
The help callback is added to print additional information specific to the init program.
The process thread signal is going to be a new callback that the init program can use to define custom behavior.
This custom behavior will utilize the special shutdown/reboot/ctrl-alt-delete signals.
The init program will be handling more signals than the controller program.
(I may want to consider looking into supporting more signals for the controller program as well.)
build_libraries_static-level -l:libfll_2.a -l:libfll_1.a -l:libfll_0.a -l:libcap.a
build_libraries_static-monolithic -l:libfll.a -l:libcap.a
-build_sources_program config.c main.c init.c string.c
+build_sources_program config.c main.c init.c print.c signal.c string.c
-build_sources_headers init.h string.h
+build_sources_headers init.h print.h signal.h string.h
build_sources_documentation man
//#define _di_fll_program_standard_set_down_
//#define _di_fll_program_standard_set_up_
//#define _di_fll_program_standard_signal_handle_
-//#define _di_fll_program_standard_signal_received_
+#define _di_fll_program_standard_signal_received_
//#define _di_fll_program_standard_signal_received_wait_
#define _di_private_inline_f_print_to_error_
#define _di_private_inline_private_f_print_to_error_
build_sources_program program/controller/main/thread.c program/controller/main/thread/cleanup.c program/controller/main/thread/control.c program/controller/main/thread/entry.c program/controller/main/thread/instance.c program/controller/main/thread/is.c program/controller/main/thread/rule.c program/controller/main/thread/signal.c
build_sources_program program/controller/main/validate.c
-build_sources_program program/controller/init/config.c program/controller/init/main.c program/controller/init/init.c program/controller/init/string.c
+build_sources_program program/controller/init/config.c program/controller/init/main.c program/controller/init/init.c program/controller/init/print.c program/controller/init/signal.c program/controller/init/string.c
build_sources_documentation man
f_console_parameter_t parameters[] = controller_console_parameter_t_initialize;
+ data.callback.print_message_help = 0;
+ data.callback.process_entry_setup = 0;
+ data.callback.process_thread_signal = &controller_thread_signal;
+
data.program.parameters.array = parameters;
data.program.parameters.used = controller_parameter_total_d;
data.program.environment = envp;
// Controller includes.
#include <program/controller/main/controller.h>
+#include <program/controller/init/print.h>
+#include <program/controller/init/signal.h>
#include <program/controller/init/string.h>
#ifdef __cplusplus
data.program.pipe = fll_program_data_pipe_input_e;
}
+ data.callback.print_message_help = &controller_init_print_message_help;
data.callback.process_entry_setup = &controller_init_process_entry_setup;
+ data.callback.process_thread_signal = &controller_init_signal_thread;
+
data.process.entry.pid = controller_entry_pid_disable_e;
data.process.entry.show = controller_entry_show_init_e;
data.process.mode = controller_process_mode_service_e;
- data.setting.flag &= ~controller_main_flag_interruptible_d;
+ data.setting.flag |= controller_main_flag_interruptible_d;
- fll_program_standard_set_up(&data.program);
+ controller_init_signal_set_up(&data);
f_file_umask_get(&data.program.umask);
--- /dev/null
+#include "init.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_controller_init__print_message_help_
+ f_status_t controller_init_print_message_help(fl_print_t * const print) {
+
+ if (!print) return F_status_set_error(F_output_not);
+
+ f_file_stream_lock(print->to);
+
+ controller_print_message_help_standard(print);
+
+ controller_print_message_help_note_simulate(print);
+ f_print_dynamic_raw(f_string_eol_s, print->to);
+
+ controller_print_message_help_note_interrupt(print);
+ fl_print_format(" Using the %[%r%r%] parameter may prevent the init program from receiving reboot and shutdown commands via signals.%r%r", print->to, print->set->notable, f_console_symbol_long_normal_s, controller_long_uninterruptible_s, print->set->notable, f_string_eol_s, f_string_eol_s);
+
+ controller_print_message_help_note_pid(print);
+
+ f_file_stream_flush(print->to);
+ f_file_stream_unlock(print->to);
+
+ return F_okay;
+ }
+#endif // _di_controller_init__print_message_help_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Provides print functionality.
+ *
+ * This is auto-included and should not need to be explicitly included.
+ */
+#ifndef _controller_init_print_h
+#define _controller_init_print_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Print help specific to the Init program.
+ *
+ * @param print
+ * The output structure to print to.
+ *
+ * This requires print.custom to be controller_t.
+ *
+ * This does not alter print.custom.setting.state.status.
+ *
+ * @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.
+ */
+#ifndef _di_controller_init__print_message_help_
+ extern f_status_t controller_init_print_message_help(fl_print_t * const print);
+#endif // _di_controller_init__print_message_help_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_init_print_h
--- /dev/null
+#include "init.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_controller_init_signal_set_up_
+ f_status_t controller_init_signal_set_up(controller_t * const main) {
+
+ if (!main) return F_status_set_error(F_parameter);
+
+ f_signal_set_empty(&main->program.signal.set);
+ f_signal_set_add(F_signal_abort, &main->program.signal.set);
+ f_signal_set_add(F_signal_broken_pipe, &main->program.signal.set);
+ f_signal_set_add(F_signal_child, &main->program.signal.set);
+ f_signal_set_add(F_signal_continue, &main->program.signal.set);
+ f_signal_set_add(F_signal_hangup, &main->program.signal.set);
+ f_signal_set_add(F_signal_interrupt, &main->program.signal.set);
+ f_signal_set_add(F_signal_keyboard_stop, &main->program.signal.set);
+ f_signal_set_add(F_signal_power_failure, &main->program.signal.set);
+ f_signal_set_add(F_signal_quit, &main->program.signal.set);
+ f_signal_set_add(F_signal_stop, &main->program.signal.set);
+ f_signal_set_add(F_signal_termination, &main->program.signal.set);
+ f_signal_set_add(F_signal_user_1, &main->program.signal.set);
+ f_signal_set_add(F_signal_user_2, &main->program.signal.set);
+
+ f_status_t status = f_signal_mask(SIG_BLOCK, &main->program.signal.set, 0);
+ if (F_status_is_error(status)) return status;
+
+ status = f_signal_open(&main->program.signal);
+
+ // If there is an error opening a signal descriptor, then do not handle signals.
+ if (F_status_is_error(status)) {
+ f_signal_mask(SIG_UNBLOCK, &main->program.signal.set, 0);
+ f_signal_close(&main->program.signal);
+
+ return status;
+ }
+
+ // Unblock all other signals.
+ memset(&main->program.signal.set, 0, sizeof(sigset_t));
+
+ f_signal_set_fill(&main->program.signal.set);
+ f_signal_set_delete(F_signal_abort, &main->program.signal.set);
+ f_signal_set_delete(F_signal_broken_pipe, &main->program.signal.set);
+ f_signal_set_delete(F_signal_child, &main->program.signal.set);
+ f_signal_set_delete(F_signal_continue, &main->program.signal.set);
+ f_signal_set_delete(F_signal_hangup, &main->program.signal.set);
+ f_signal_set_delete(F_signal_interrupt, &main->program.signal.set);
+ f_signal_set_delete(F_signal_keyboard_stop, &main->program.signal.set);
+ f_signal_set_delete(F_signal_power_failure, &main->program.signal.set);
+ f_signal_set_delete(F_signal_quit, &main->program.signal.set);
+ f_signal_set_delete(F_signal_stop, &main->program.signal.set);
+ f_signal_set_delete(F_signal_termination, &main->program.signal.set);
+ f_signal_set_delete(F_signal_user_1, &main->program.signal.set);
+ f_signal_set_delete(F_signal_user_2, &main->program.signal.set);
+
+ status = f_signal_mask(SIG_UNBLOCK, &main->program.signal.set, 0);
+ if (F_status_is_error(status)) return status;
+
+ return F_okay;
+ }
+#endif // _di_controller_init_signal_set_up_
+
+#ifndef _di_controller_init_signal_thread_
+ void controller_init_signal_thread(controller_t * const main, const uint8_t is_normal) {
+
+ if (!main) return;
+ if (!controller_thread_is_enabled(&main->thread, is_normal)) return;
+ if (!(main->setting.flag & controller_main_flag_interruptible_d)) return;
+
+ siginfo_t information;
+ f_time_spec_t time = f_time_spec_t_initialize;
+
+ while (controller_thread_is_enabled(&main->thread, is_normal)) {
+
+ memset((void *) &information, 0, sizeof(siginfo_t));
+
+ controller_time_now(controller_thread_timeout_exit_ready_seconds_d, controller_thread_timeout_exit_ready_nanoseconds_d, &time);
+
+ // Allow thread to be interrupted and auto-cancelled while sleeping.
+ f_thread_cancel_state_set(PTHREAD_CANCEL_ASYNCHRONOUS, 0);
+
+ if (f_signal_wait_until(&main->program.signal.set, &time, &information) == F_time_out) continue;
+
+ // Prevent thread from being interrupted and auto-cancelled.
+ f_thread_cancel_state_set(PTHREAD_CANCEL_DEFERRED, 0);
+
+ // Reap zombie processes.
+ if (information.si_signo == F_signal_child) {
+ // @todo verify that this process id is a valid child process.
+ // @todo send F_signal_terminate first?
+ // @todo a waitpid() needs to be performed to check to see how to handle the child signal.
+ //f_signal_send(F_signal_kill, information.si_pid);
+ // @todo move this to a function and identify any pid files and clear it from the process array (see calls like: status = controller_file_pid_read(instance->path_pids.array[j], &pid););
+ }
+
+ if (information.si_signo == F_signal_interrupt || information.si_signo == F_signal_abort || information.si_signo == F_signal_quit || information.si_signo == F_signal_termination) {
+ main->thread.signal = information.si_signo;
+
+ controller_thread_instance_cancel(main, is_normal, controller_thread_cancel_signal_e);
+
+ break;
+ }
+ } // while
+ }
+#endif // _di_controller_init_signal_thread_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/**
+ * FLL - Level 3
+ *
+ * Project: Controller
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Provides signal functionality.
+ *
+ * This is auto-included and should not need to be explicitly included.
+ */
+#ifndef _controller_init_signal_h
+#define _controller_init_signal_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Perform standard setup with custom signals.
+ *
+ * This is a modified version of fll_program_standard_set_up().
+ *
+ * @param main
+ * The main program data.
+ *
+ * Must not be NULL.
+ *
+ * @return
+ * F_okay on success.
+ *
+ * F_parameter (with error bit) if a parameter is invalid.
+ *
+ * Errors (with error bit) from: f_signal_mask().
+ * Errors (with error bit) from: f_signal_open().
+ *
+ * @see f_signal_mask()
+ * @see f_signal_open()
+ * @see f_signal_set_add()
+ * @see f_signal_set_delete()
+ * @see f_signal_set_empty()
+ * @see f_signal_set_fill()
+ */
+#ifndef _di_controller_init_signal_set_up_
+ extern f_status_t controller_init_signal_set_up(controller_t * const main);
+#endif // _di_controller_init_signal_set_up_
+
+/**
+ * Thread for handling signals/interrupts for the init program.
+ *
+ * @param main
+ * The main program data.
+ *
+ * Must not be NULL.
+ * @param is_normal
+ * If TRUE, then process as if this operates during a normal operation (Entry and Control).
+ * If FALSE, then process as if this operates during an Exit operation.
+ */
+#ifndef _di_controller_init_signal_thread_
+ extern void controller_init_signal_thread(controller_t * const main, const uint8_t is_normal);
+#endif // _di_controller_init_signal_thread_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _controller_init_signal_h
* The Controller callbacks.
*
* Properties:
- * - process_entry_setup: Perform any optional initialization on the entry.
+ * - print_message_help: Callback for printing the help message.
+ * - process_entry_setup: Perform any optional initialization on the entry.
+ * - process_thread_signal: Handle signals for threaded operation.
*/
#ifndef _di_controller_t_
typedef struct {
+ f_status_t (*print_message_help)(fl_print_t * const print);
+
f_status_t (*process_entry_setup)(controller_t * const main, controller_entry_t * const entry);
+ void (*process_thread_signal)(controller_t * const main, const uint8_t is_normal);
} controller_callback_t;
#define controller_callback_t_initialize \
{ \
0, \
+ 0, \
+ 0, \
}
#endif // _di_controller_t_
#include <program/controller/main/print/warning/rule/action.h>
#include <program/controller/main/print/warning/rule/item.h>
#include <program/controller/main/print/warning/rule/setting.h>
-#include <program/controller/main/signal.h>
#include <program/controller/main/status.h>
#include <program/controller/main/time.h>
#include <program/controller/main/thread/cleanup.h>
#endif
#ifndef _di_controller_print_message_help_
- f_status_t controller_print_message_help(fl_print_t * const print, const uint8_t uninterrupt) {
+ f_status_t controller_print_message_help(fl_print_t * const print) {
if (!print) return F_status_set_error(F_output_not);
f_file_stream_lock(print->to);
+ controller_print_message_help_standard(print);
+
+ controller_print_message_help_note_simulate(print);
+ f_print_dynamic_raw(f_string_eol_s, print->to);
+
+ controller_print_message_help_note_interrupt(print);
+ f_print_dynamic_raw(f_string_eol_s, print->to);
+
+ controller_print_message_help_note_pid(print);
+
+ f_file_stream_flush(print->to);
+ f_file_stream_unlock(print->to);
+
+ return F_okay;
+ }
+#endif // _di_controller_print_message_help_
+
+#ifndef _di_controller_print_message_help_note_interrupt_
+ f_status_t controller_print_message_help_note_interrupt(fl_print_t * const print) {
+
+ if (!print) return F_status_set_error(F_output_not);
+
+ fl_print_format(" The default interrupt behavior is to operate as if the %[%r%r%] parameter is passed.%r", print->to, print->set->notable, f_console_symbol_long_normal_s, controller_long_interruptible_s, print->set->notable, f_string_eol_s);
+
+ return F_okay;
+ }
+#endif // _di_controller_print_message_help_note_interrupt_
+
+#ifndef _di_controller_print_message_help_note_pid_
+ f_status_t controller_print_message_help_note_pid(fl_print_t * const print) {
+
+ if (!print) return F_status_set_error(F_output_not);
+
+ fl_print_format(" Specify an empty string for the %[%r%r%] parameter to disable pid file creation for this program.%r", print->to, print->set->notable, f_console_symbol_long_normal_s, controller_long_pid_s, print->set->notable, f_string_eol_s);
+
+ return F_okay;
+ }
+#endif // _di_controller_print_message_help_note_pid_
+
+#ifndef _di_controller_print_message_help_note_simulate_
+ f_status_t controller_print_message_help_note_simulate(fl_print_t * const print) {
+
+ if (!print) return F_status_set_error(F_output_not);
+
+ fl_print_format("%r When both the %[%r%r%] parameter and the", print->to, f_string_eol_s, print->set->notable, f_console_symbol_long_normal_s, controller_long_simulate_s, print->set->notable);
+ fl_print_format(" %[%r%r%] parameter are specified, then additional information on each would be executed Rule is printed but no simulation is performed.%r", print->to, print->set->notable, f_console_symbol_long_normal_s, controller_long_validate_s, print->set->notable, f_string_eol_s);
+
+ return F_okay;
+ }
+#endif // _di_controller_print_message_help_note_simulate_
+
+#ifndef _di_controller_print_message_help_standard_
+ f_status_t controller_print_message_help_standard(fl_print_t * const print) {
+
+ if (!print) return F_status_set_error(F_output_not);
+
fll_program_print_help_header(print, controller_program_name_long_s, controller_program_version_s);
fll_program_print_help_option_standard(print);
fll_program_print_help_usage(print, controller_program_name_s, f_string_empty_s);
- fl_print_format("%r When both the %[%r%r%] parameter and the", print->to, f_string_eol_s, print->set->notable, f_console_symbol_long_normal_s, controller_long_simulate_s, print->set->notable);
- fl_print_format(" %[%r%r%] parameter are specified, then additional information on each would be executed Rule is printed but no simulation is performed.%r%r", print->to, print->set->notable, f_console_symbol_long_normal_s, controller_long_validate_s, print->set->notable, f_string_eol_s, f_string_eol_s);
-
- fl_print_format(" The default interrupt behavior is to operate as if the %[%r%r%] parameter is passed.%r%r", print->to, print->set->notable, f_console_symbol_long_normal_s, uninterrupt ? controller_long_uninterruptible_s : controller_long_interruptible_s, print->set->notable, f_string_eol_s, f_string_eol_s);
-
- fl_print_format(" Specify an empty string for the %[%r%r%] parameter to disable pid file creation for this program.%r", print->to, print->set->notable, f_console_symbol_long_normal_s, controller_long_pid_s, print->set->notable, f_string_eol_s);
-
- f_file_stream_flush(print->to);
- f_file_stream_unlock(print->to);
-
return F_okay;
}
-#endif // _di_controller_print_message_help_
+#endif // _di_controller_print_message_help_standard_
#ifdef __cplusplus
} // extern "C"
* This requires print.custom to be controller_t.
*
* This does not alter print.custom.setting.state.status.
- * @param uninterrupt
- * Set to F_true to print that the default behavior is uninterruptible.
- * Otherwise, print that the default behavior is interruptible.
*
* @return
* F_okay on success.
* F_output_not (with error bit) if setting is NULL.
*/
#ifndef _di_controller_print_message_help_
- extern f_status_t controller_print_message_help(fl_print_t * const print, const uint8_t uninterrupt);
+ extern f_status_t controller_print_message_help(fl_print_t * const print);
#endif // _di_controller_print_message_help_
+/**
+ * Print interrupt note help.
+ *
+ * This expects the output to be already locked.
+ *
+ * @param print
+ * The output structure to print to.
+ *
+ * This requires print.custom to be controller_t.
+ *
+ * This does not alter print.custom.setting.state.status.
+ *
+ * @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.
+ */
+#ifndef _di_controller_print_message_help_note_interrupt_
+ extern f_status_t controller_print_message_help_note_interrupt(fl_print_t * const print);
+#endif // _di_controller_print_message_help_note_interrupt_
+
+/**
+ * Print PID note help.
+ *
+ * This expects the output to be already locked.
+ *
+ * @param print
+ * The output structure to print to.
+ *
+ * This requires print.custom to be controller_t.
+ *
+ * This does not alter print.custom.setting.state.status.
+ *
+ * @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.
+ */
+#ifndef _di_controller_print_message_help_note_pid_
+ extern f_status_t controller_print_message_help_note_pid(fl_print_t * const print);
+#endif // _di_controller_print_message_help_note_pid_
+
+/**
+ * Print simulate note help.
+ *
+ * This expects the output to be already locked.
+ *
+ * @param print
+ * The output structure to print to.
+ *
+ * This requires print.custom to be controller_t.
+ *
+ * This does not alter print.custom.setting.state.status.
+ *
+ * @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.
+ */
+#ifndef _di_controller_print_message_help_note_simulate_
+ extern f_status_t controller_print_message_help_note_simulate(fl_print_t * const print);
+#endif // _di_controller_print_message_help_note_simulate_
+
+/**
+ * Print standard help parameters and usage without the additional notes.
+ *
+ * This expects the output to be already locked.
+ *
+ * @param print
+ * The output structure to print to.
+ *
+ * This requires print.custom to be controller_t.
+ *
+ * This does not alter print.custom.setting.state.status.
+ *
+ * @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.
+ */
+#ifndef _di_controller_print_message_help_standard_
+ extern f_status_t controller_print_message_help_standard(fl_print_t * const print);
+#endif // _di_controller_print_message_help_standard_
+
#ifdef __cplusplus
} // extern "C"
#endif
fl_print_format(" %r", print->to, *string);
}
- fl_print_format("%r", print->to, f_string_eol_s);
+ f_print_dynamic_raw(f_string_eol_s, print->to);
// Session.
fl_print_format(" %r", print->to, *string, f_string_eol_s);
}
- fl_print_format("%r", print->to, f_string_eol_s);
+ f_print_dynamic_raw(f_string_eol_s, print->to);
// Show.
fl_print_format(" %r", print->to, *string, f_string_eol_s);
}
- fl_print_format("%r", print->to, f_string_eol_s);
+ f_print_dynamic_raw(f_string_eol_s, print->to);
// Pid.
fl_print_format(" %r", print->to, *string);
}
- fl_print_format("%r", print->to, f_string_eol_s);
+ f_print_dynamic_raw(f_string_eol_s, print->to);
// Pid File.
fl_print_format(" %r", print->to, main->process.path_pid);
}
- fl_print_format("%r", print->to, f_string_eol_s);
+ f_print_dynamic_raw(f_string_eol_s, print->to);
// Control.
fl_print_format(" %Q", print->to, main->process.path_control);
}
- fl_print_format("%r", print->to, f_string_eol_s);
+ f_print_dynamic_raw(f_string_eol_s, print->to);
// Control Has.
fl_print_format(" %r", print->to, controller_readonly_s);
}
- fl_print_format("%r", print->to, f_string_eol_s);
+ f_print_dynamic_raw(f_string_eol_s, print->to);
// Control User.
fl_print_format(" %u", print->to, (unsigned int) main->process.control.user);
}
- fl_print_format("%r", print->to, f_string_eol_s);
+ f_print_dynamic_raw(f_string_eol_s, print->to);
// Control Group.
fl_print_format(" %u", print->to, (unsigned int) main->process.control.group);
}
- fl_print_format("%r", print->to, f_string_eol_s);
+ f_print_dynamic_raw(f_string_eol_s, print->to);
// Control Mode.
}
}
- fl_print_format("%r", print->to, f_string_eol_s);
+ f_print_dynamic_raw(f_string_eol_s, print->to);
// Timeout: Exit.
fl_print_format(" %ul", print->to, entry->timeout_exit, f_string_eol_s);
}
- fl_print_format("%r", print->to, f_string_eol_s);
+ f_print_dynamic_raw(f_string_eol_s, print->to);
// Timeout: Kill.
fl_print_format(" %ul", print->to, entry->timeout_kill, f_string_eol_s);
}
- fl_print_format("%r", print->to, f_string_eol_s);
+ f_print_dynamic_raw(f_string_eol_s, print->to);
// Timeout: Start.
fl_print_format(" %ul", print->to, entry->timeout_start, f_string_eol_s);
}
- fl_print_format("%r", print->to, f_string_eol_s);
+ f_print_dynamic_raw(f_string_eol_s, print->to);
// Timeout: Stop.
fl_print_format(" %ul", print->to, entry->timeout_stop, f_string_eol_s);
}
- fl_print_format("%r", print->to, f_string_eol_s);
+ f_print_dynamic_raw(f_string_eol_s, print->to);
// Define.
}
}
- fl_print_format("%r", print->to, f_string_eol_s);
+ f_print_dynamic_raw(f_string_eol_s, print->to);
// Parameters.
fl_print_format(" %Q", print->to, action->parameters.array[0], f_string_eol_s);
}
- fl_print_format("%r", print->to, f_string_eol_s);
+ f_print_dynamic_raw(f_string_eol_s, print->to);
}
else if (raw) {
for (k = 0; k < action->parameters.used; ++k) {
fl_print_format(" %Q", print->to, action->parameters.array[0], f_string_eol_s);
}
- fl_print_format("%r", print->to, f_string_eol_s);
+ f_print_dynamic_raw(f_string_eol_s, print->to);
// Parameter, File.
fl_print_format(" %Q", print->to, action->parameters.array[1], f_string_eol_s);
}
- fl_print_format("%r", print->to, f_string_eol_s);
+ f_print_dynamic_raw(f_string_eol_s, print->to);
}
fl_print_format(" }%r", print->to, f_string_eol_s);
}
} // for
- fl_print_format("%r", print->to, f_string_eol_s);
+ f_print_dynamic_raw(f_string_eol_s, print->to);
}
else {
fl_print_format(" %[%r%] %Q%r", print->to, print->set->important, controller_engine_s, print->set->important, rule->engine, f_string_eol_s);
if (main->setting.flag & controller_main_flag_version_copyright_help_d) {
if (main->setting.flag & controller_main_flag_help_d) {
- controller_print_message_help(&main->program.message, F_false);
+ if (main->callback.print_message_help) {
+ main->callback.print_message_help(&main->program.message);
+ }
+ else {
+ controller_print_message_help(&main->program.message);
+ }
}
else if (main->setting.flag & controller_main_flag_version_d) {
fll_program_print_version(&main->program.message, controller_program_version_s);
/**
* Execute main program process, starting all threads, waiting on threads, and handling requests.
*
- * If main.signal is non-zero, then this blocks and handles the following signals:
+ * If main.signal is non-zero, then this blocks and handles the signals defined in the main.program.signal.set.
+ * The standard signals are (see the init program for its modifications on main.program.signal.set):
* - F_signal_abort
* - F_signal_broken_pipe
* - F_signal_hangup
f_thread_cancel_state_set(PTHREAD_CANCEL_DEFERRED, 0);
- controller_thread_signal((controller_t *) argument, F_true);
+ if (argument && ((controller_t *) argument)->callback.process_thread_signal) {
+ ((controller_t *) argument)->callback.process_thread_signal((controller_t *) argument, F_true);
+ }
return 0;
}
f_thread_cancel_state_set(PTHREAD_CANCEL_DEFERRED, 0);
- controller_thread_signal((controller_t *) argument, F_false);
+ if (argument && ((controller_t *) argument)->callback.process_thread_signal) {
+ ((controller_t *) argument)->callback.process_thread_signal((controller_t *) argument, F_false);
+ }
return 0;
}