The pid file may be created before the filesystem is ready and it may not be deleted when the system shuts down.
This then prevents the system from booting due to init failures.
Provide rule setting for fine tuning the control over how to handle the pid file.
Now, when running "as init", the pid entry setting by default designates to only utilize the pid file when "ready".
Previously, the pid file was always being checked for before the entry is even processed.
This prevented even waiting on the "ready" action because the entry is bailing out before even being processed.
There already is a "verbose" that prints the execution of programs.
This does not, however, start by default.
Provide a "show" setting for toggling this behavior to print some of the verbose messages when in "init" "show" mode.
Update the constant strings and related variables.
The ready behavior needs to be properly set.
As far as I can tell, the logic seemed odd, if not wrong.
Remove one of the ready checks and cleanup the ready check for the explicit ready action.
Update the prebuilt rules for terminals.
For now, there will be separate terminal files to execute.
There should be a variable substitution later on to not require multiple files.
For example, behavior is now:
"rule terminal one", found in rules/terminal/one.rule
"rule terminal two", found in rules/terminal/two.rule
This could better be something like:
"rule terminal tty/1", found in rules/terminal/tty.rule
"rule terminal tty/2", found in rules/terminal/tty.rule
Cleanup and update the documentation.
}
}
- // The interruptable default is dependent on the "as init" execution state.
+ // Handle defaults dependent on the "as init" execution state.
if (main->as_init) {
+ setting.entry.pid = controller_entry_pid_disable;
+ setting.entry.show = controller_entry_show_init;
+
if (main->parameters[controller_parameter_interruptable].result == f_console_result_found) {
setting.interruptable = F_true;
}
const f_string_t controller_string_deadline_s = controller_string_deadline;
const f_string_t controller_string_default_s = controller_string_default;
const f_string_t controller_string_define_s = controller_string_define;
+ const f_string_t controller_string_disable_s = controller_string_disable;
const f_string_t controller_string_entry_s = controller_string_entry;
const f_string_t controller_string_entries_s = controller_string_entries;
const f_string_t controller_string_environment_s = controller_string_environment;
- const f_string_t controller_string_existing_s = controller_string_existing;
const f_string_t controller_string_execute_s = controller_string_execute;
+ const f_string_t controller_string_existing_s = controller_string_existing;
const f_string_t controller_string_exit_s = controller_string_exit;
const f_string_t controller_string_exits_s = controller_string_exits;
const f_string_t controller_string_fail_s = controller_string_fail;
const f_string_t controller_string_how_s = controller_string_how;
const f_string_t controller_string_idle_s = controller_string_idle;
const f_string_t controller_string_item_s = controller_string_item;
+ const f_string_t controller_string_init_s = controller_string_init;
const f_string_t controller_string_kill_s = controller_string_kill;
const f_string_t controller_string_limit_s = controller_string_limit;
const f_string_t controller_string_locks_s = controller_string_locks;
const f_string_t controller_string_nice_s = controller_string_nice;
const f_string_t controller_string_no_s = controller_string_no;
const f_string_t controller_string_nofile_s = controller_string_nofile;
+ const f_string_t controller_string_normal_s = controller_string_normal;
const f_string_t controller_string_nproc_s = controller_string_nproc;
const f_string_t controller_string_on_s = controller_string_on;
const f_string_t controller_string_optional_s = controller_string_optional;
const f_string_t controller_string_other_s = controller_string_other;
const f_string_t controller_string_parameter_s = controller_string_parameter;
+ const f_string_t controller_string_parameters_s = controller_string_parameters;
const f_string_t controller_string_path_s = controller_string_path;
const f_string_t controller_string_pause_s = controller_string_pause;
+ const f_string_t controller_string_pid_s = controller_string_pid;
const f_string_t controller_string_pid_file_s = controller_string_pid_file;
const f_string_t controller_string_processor_s = controller_string_processor;
const f_string_t controller_string_program_s = controller_string_program;
const f_string_t controller_string_script_s = controller_string_script;
const f_string_t controller_string_service_s = controller_string_service;
const f_string_t controller_string_setting_s = controller_string_setting;
+ const f_string_t controller_string_show_s = controller_string_show;
const f_string_t controller_string_sigpending_s = controller_string_sigpending;
const f_string_t controller_string_stack_s = controller_string_stack;
const f_string_t controller_string_start_s = controller_string_start;
#define controller_string_deadline "deadline"
#define controller_string_default "default"
#define controller_string_define "define"
+ #define controller_string_disable "disable"
#define controller_string_entry "entry"
#define controller_string_entries "entries"
#define controller_string_environment "environment"
#define controller_string_how "how"
#define controller_string_idle "idle"
#define controller_string_item "item"
+ #define controller_string_init "init"
#define controller_string_kill "kill"
#define controller_string_limit "limit"
#define controller_string_locks "locks"
#define controller_string_nice "nice"
#define controller_string_no "no"
#define controller_string_nofile "nofile"
+ #define controller_string_normal "normal"
#define controller_string_nproc "nproc"
#define controller_string_on "on"
#define controller_string_optional "optional"
#define controller_string_other "other"
#define controller_string_parameter "parameter"
+ #define controller_string_parameters "parameters"
#define controller_string_path "path"
#define controller_string_pause "pause"
+ #define controller_string_pid "pid"
#define controller_string_pid_file "pid_file"
#define controller_string_processor "processor"
#define controller_string_program "program"
#define controller_string_service "service"
#define controller_string_setting "setting"
#define controller_string_sigpending "sigpending"
+ #define controller_string_show "show"
#define controller_string_stack "stack"
#define controller_string_start "start"
#define controller_string_stop "stop"
#define controller_string_cpu_length 3
#define controller_string_data_length 4
#define controller_string_deadline_length 8
- #define controller_string_define_length 6
#define controller_string_default_length 7
+ #define controller_string_define_length 6
+ #define controller_string_disable_length 7
#define controller_string_entry_length 5
#define controller_string_entries_length 7
#define controller_string_environment_length 11
#define controller_string_fsize_length 5
#define controller_string_full_path_length 9
#define controller_string_group_length 5
+ #define controller_string_groups_length 6
#define controller_string_how_length 3
#define controller_string_idle_length 4
+ #define controller_string_init_length 4
#define controller_string_item_length 4
#define controller_string_kill_length 4
#define controller_string_limit_length 5
#define controller_string_nice_length 4
#define controller_string_no_length 2
#define controller_string_nofile_length 6
+ #define controller_string_normal_length 6
#define controller_string_nproc_length 5
#define controller_string_on_length 2
#define controller_string_optional_length 8
#define controller_string_other_length 5
#define controller_string_parameter_length 9
+ #define controller_string_parameters_length 10
#define controller_string_path_length 4
#define controller_string_pause_length 5
+ #define controller_string_pid_length 3
#define controller_string_pid_file_length 8
#define controller_string_processor_length 9
#define controller_string_program_length 7
#define controller_string_script_length 6
#define controller_string_service_length 7
#define controller_string_setting_length 7
+ #define controller_string_show_length 4
#define controller_string_sigpending_length 10
#define controller_string_stack_length 5
#define controller_string_start_length 5
extern const f_string_t controller_string_consider_s;
extern const f_string_t controller_string_control_s;
extern const f_string_t controller_string_control_group_s;
- extern const f_string_t controller_string_cpu_s;
extern const f_string_t controller_string_core_s;
+ extern const f_string_t controller_string_cpu_s;
extern const f_string_t controller_string_data_s;
extern const f_string_t controller_string_deadline_s;
extern const f_string_t controller_string_default_s;
extern const f_string_t controller_string_define_s;
+ extern const f_string_t controller_string_disable_s;
extern const f_string_t controller_string_entry_s;
extern const f_string_t controller_string_entries_s;
extern const f_string_t controller_string_environment_s;
extern const f_string_t controller_string_groups_s;
extern const f_string_t controller_string_how_s;
extern const f_string_t controller_string_idle_s;
+ extern const f_string_t controller_string_init_s;
extern const f_string_t controller_string_item_s;
extern const f_string_t controller_string_kill_s;
extern const f_string_t controller_string_limit_s;
extern const f_string_t controller_string_nice_s;
extern const f_string_t controller_string_no_s;
extern const f_string_t controller_string_nofile_s;
+ extern const f_string_t controller_string_normal_s;
extern const f_string_t controller_string_nproc_s;
extern const f_string_t controller_string_on_s;
extern const f_string_t controller_string_optional_s;
extern const f_string_t controller_string_other_s;
extern const f_string_t controller_string_parameter_s;
+ extern const f_string_t controller_string_parameters_s;
extern const f_string_t controller_string_path_s;
extern const f_string_t controller_string_pause_s;
+ extern const f_string_t controller_string_pid_s;
extern const f_string_t controller_string_pid_file_s;
extern const f_string_t controller_string_processor_s;
extern const f_string_t controller_string_program_s;
extern const f_string_t controller_string_script_s;
extern const f_string_t controller_string_service_s;
extern const f_string_t controller_string_setting_s;
+ extern const f_string_t controller_string_show_s;
extern const f_string_t controller_string_sigpending_s;
extern const f_string_t controller_string_stack_s;
extern const f_string_t controller_string_start_s;
* Entry and Exit files are essentially the same structure with minor differences in settings and behavior.
* The structure is identical and due to lacking any particularly good name to represent both "entry" or "exit", the name "entry" is being used for both.
*
+ * controller_entry_pid_*:
+ * - disable: Do not check for or create a PID file to represent the entry execution.
+ * - require: Check to see if the PID file exists for an entry at startup and then when "ready" create a pid file, display error on pid file already exists or on failure and then fail.
+ * - ready: When "ready" create a pid file, display error on failure and then fail (does not check if PID file exists).
+ *
+ * controller_entry_show_*:
+ * - normal: Do not print anything other than warnings and errors, but allow executed programs and scripts to output however they like.
+ * - init: Print like an init program, printing status of entry and rules as they are being started, stopped, etc...
+ *
* status: The overall status.
+ * pid: The PID file generation setting.
+ * show: The show setting for controlling what to show when executing entry items and rules.
* items: The array of entry items.
*/
#ifndef _di_controller_entry_t_
+ enum {
+ controller_entry_pid_disable = 0,
+ controller_entry_pid_require,
+ controller_entry_pid_ready,
+ };
+
+ enum {
+ controller_entry_show_normal = 0,
+ controller_entry_show_init,
+ };
+
typedef struct {
f_status_t status;
+ uint8_t pid;
+ uint8_t show;
+
controller_entry_items_t items;
} controller_entry_t;
#define controller_entry_t_initialize { \
F_known_not, \
+ controller_entry_pid_require, \
+ controller_entry_show_normal, \
controller_entry_items_t_initialize, \
}
#endif // _di_controller_entry_t_
#ifndef _di_controller_perform_ready_
f_status_t controller_perform_ready(const bool is_entry, controller_global_t global, controller_cache_t *cache) {
- f_status_t status = F_none;
-
- // only create pid file when not in validate mode.
- if (is_entry && global.main->parameters[controller_parameter_validate].result == f_console_result_none && global.setting->path_pid.used) {
-
- status = controller_file_pid_create(global.main->pid, global.setting->path_pid);
+ // Only create pid file when not in validate mode.
+ if (!is_entry || global.setting->entry.pid == controller_entry_pid_disable || global.main->parameters[controller_parameter_validate].result != f_console_result_none || !global.setting->path_pid.used) {
+ return F_none;
+ }
- // report pid file error but because this could be an "init" program, consider the pid file as optional and continue on.
- if (F_status_is_error(status)) {
+ f_status_t status = controller_file_pid_create(global.main->pid, global.setting->path_pid);
- // always return immediately on memory errors.
- if (F_status_set_fine(status) == F_memory_not) {
- if (global.main->error.verbosity != f_console_verbosity_quiet) {
- controller_print_lock(global.main->error.to, global.thread);
+ // Report pid file error but because this could be an "init" program, consider the pid file as optional and continue on.
+ if (F_status_is_error(status)) {
- controller_error_file_print(global.main->error, F_status_set_fine(status), "controller_file_pid_create", F_true, global.setting->path_pid.string, "create", fll_error_file_type_file, 0);
+ // Always return immediately on memory errors.
+ if (F_status_set_fine(status) == F_memory_not) {
+ if (global.main->error.verbosity != f_console_verbosity_quiet) {
+ controller_print_lock(global.main->error.to, global.thread);
- flockfile(global.main->error.to.stream);
+ controller_error_file_print(global.main->error, F_status_set_fine(status), "controller_file_pid_create", F_true, global.setting->path_pid.string, "create", fll_error_file_type_file, 0);
- controller_entry_error_print_cache(is_entry, global.main->error, cache->action);
+ flockfile(global.main->error.to.stream);
- controller_print_unlock_flush(global.main->error.to, global.thread);
- }
+ controller_entry_error_print_cache(is_entry, global.main->error, cache->action);
- return status;
+ controller_print_unlock_flush(global.main->error.to, global.thread);
}
- if (global.main->warning.verbosity == f_console_verbosity_debug) {
- controller_print_lock(global.main->warning.to, global.thread);
-
- if (F_status_set_fine(status) == F_read_only) {
- fl_print_format("%c%[%SThe pid file '%]", global.main->warning.to.stream, f_string_eol_s[0], global.main->warning.context, global.main->warning.prefix ? global.main->warning.prefix : f_string_empty_s, global.main->warning.context);
- fl_print_format("%[%Q%]", global.main->warning.to.stream, global.main->warning.notable, global.setting->path_pid, global.main->warning.notable);
- fl_print_format("%[' could not be written because the destination is read only.%]%c", global.main->warning.to.stream, global.main->warning.context, global.main->warning.context, f_string_eol_s[0]);
- }
- else {
- controller_error_file_print(global.main->warning, F_status_set_fine(status), "controller_file_pid_create", F_true, global.setting->path_pid.string, "create", fll_error_file_type_file, 0);
- }
+ return status;
+ }
- controller_entry_error_print_cache(is_entry, global.main->warning, cache->action);
+ if (global.main->warning.verbosity == f_console_verbosity_debug) {
+ controller_print_lock(global.main->warning.to, global.thread);
- controller_print_unlock_flush(global.main->warning.to, global.thread);
+ if (F_status_set_fine(status) == F_read_only) {
+ fl_print_format("%c%[%SThe pid file '%]", global.main->warning.to.stream, f_string_eol_s[0], global.main->warning.context, global.main->warning.prefix ? global.main->warning.prefix : f_string_empty_s, global.main->warning.context);
+ fl_print_format("%[%Q%]", global.main->warning.to.stream, global.main->warning.notable, global.setting->path_pid, global.main->warning.notable);
+ fl_print_format("%[' could not be written because the destination is read only.%]%c", global.main->warning.to.stream, global.main->warning.context, global.main->warning.context, f_string_eol_s[0]);
+ }
+ else {
+ controller_error_file_print(global.main->warning, F_status_set_fine(status), "controller_file_pid_create", F_true, global.setting->path_pid.string, "create", fll_error_file_type_file, 0);
}
- status = F_none;
- }
- else {
- global.setting->pid_created = F_true;
+ controller_entry_error_print_cache(is_entry, global.main->warning, cache->action);
+
+ controller_print_unlock_flush(global.main->warning.to, global.thread);
}
+
+ status = F_none;
+ }
+ else {
+ global.setting->pid_created = F_true;
}
return status;
uint8_t error_has = F_false;
- // this effectively sets the read for an entry and resets the ready for an exit.
+ // This effectively sets the read for an entry and resets the ready for an exit.
// @todo should there be a ready_exit instead?
// @todo the global.setting->ready in this function may need mutex lock protection.
global.setting->ready = controller_setting_ready_no;
cache->action.name_action.used = 0;
cache->action.name_item.used = 0;
- if (global->setting->ready == controller_setting_ready_yes) {
- status = controller_perform_ready(is_entry, *global, cache);
- if (F_status_is_error(status)) return status;
- }
-
macro_f_array_lengths_t_increase_by(status, cache->ats, controller_common_allocation_small)
if (F_status_is_error(status)) {
}
if (entry_action->type == controller_entry_action_type_ready) {
- if (entry_action->code & controller_entry_rule_code_wait) {
- if (global->main->parameters[controller_parameter_simulate].result == f_console_result_found || global->main->error.verbosity == f_console_verbosity_verbose) {
+ if ((entry_action->code & controller_entry_rule_code_wait) || global->setting->ready == controller_setting_ready_wait) {
+ if (global->main->parameters[controller_parameter_simulate].result == f_console_result_found || global->main->error.verbosity == f_console_verbosity_verbose || entry->show == controller_entry_show_init) {
if (global->main->error.verbosity != f_console_verbosity_quiet) {
controller_print_lock(global->main->output, global->thread);
}
}
- if (global->setting->ready == controller_setting_ready_wait) {
+ if (global->setting->ready == controller_setting_ready_yes) {
if (global->main->parameters[controller_parameter_simulate].result == f_console_result_found || global->main->error.verbosity == f_console_verbosity_verbose) {
if (global->main->error.verbosity != f_console_verbosity_quiet) {
controller_print_lock(global->main->output, global->thread);
- fl_print_format("%cWaiting before processing %s item action '", global->main->output.stream, f_string_eol_s[0], is_entry ? controller_string_entry_s : controller_string_exit_s);
+ fl_print_format("%cIgnoring %s item action '", global->main->output.stream, f_string_eol_s[0], is_entry ? controller_string_entry_s : controller_string_exit_s);
fl_print_format("%[%s%]", global->main->output.stream, global->main->context.set.title, controller_string_ready_s, global->main->context.set.title);
- fl_print_format("'.%c", global->main->output.stream, f_string_eol_s[0]);
+ fl_print_format("', state already is ready.%c", global->main->output.stream, f_string_eol_s[0]);
controller_print_unlock_flush(global->main->output, global->thread);
}
}
-
- if (global->main->parameters[controller_parameter_simulate].result == f_console_result_none) {
- status = controller_perform_ready(is_entry, *global, cache);
-
- if (F_status_is_error(status)) return status;
- }
-
- global->setting->ready = controller_setting_ready_yes;
}
- else if (global->main->parameters[controller_parameter_simulate].result == f_console_result_found || global->main->error.verbosity == f_console_verbosity_verbose) {
- if (global->main->error.verbosity != f_console_verbosity_quiet) {
- controller_print_lock(global->main->output, global->thread);
-
- fl_print_format("%cIgnoring %s item action '", global->main->output.stream, f_string_eol_s[0], is_entry ? controller_string_entry_s : controller_string_exit_s);
- fl_print_format("%[%s%]", global->main->output.stream, global->main->context.set.title, controller_string_ready_s, global->main->context.set.title);
- fl_print_format("', state already is ready.%c", global->main->output.stream, f_string_eol_s[0]);
-
- controller_print_unlock_flush(global->main->output, global->thread);
+ else {
+ if (!failsafe && (global->main->error.verbosity == f_console_verbosity_verbose || entry->show == controller_entry_show_init) && global->main->parameters[controller_parameter_simulate].result == f_console_result_none) {
+ fl_print_format("%cState is now '%[%s%]'.%c", global->main->output.stream, f_string_eol_s[0], global->main->context.set.notable, controller_string_ready_s, global->main->context.set.notable, f_string_eol_s[0]);
}
+
+ status = controller_perform_ready(is_entry, *global, cache);
+ if (F_status_is_error(status)) return status;
}
}
else if (entry_action->type == controller_entry_action_type_item) {
break;
}
else if (entry_action->type == controller_entry_action_type_consider || controller_entry_action_type_is_rule(entry_action->type)) {
-
status_lock = controller_lock_write(is_entry, global->thread, &global->thread->lock.rule);
if (status_lock == F_signal || F_status_is_error(status_lock)) {
f_thread_unlock(&global->thread->lock.rule);
- if (global->main->parameters[controller_parameter_simulate].result == f_console_result_found || global->main->error.verbosity == f_console_verbosity_verbose) {
+ if (global->main->parameters[controller_parameter_simulate].result == f_console_result_found || global->main->error.verbosity == f_console_verbosity_verbose || (entry->show == controller_entry_show_init && entry_action->type != controller_entry_action_type_consider)) {
if (global->main->error.verbosity != f_console_verbosity_quiet) {
controller_print_lock(global->main->output, global->thread);
- fl_print_format("%c%s %s item rule '", global->main->output.stream, f_string_eol_s[0], entry_action->type == controller_entry_action_type_consider ? "Considering" : "Processing", is_entry ? controller_string_entry_s : controller_string_exit_s);
- fl_print_format("%[%Q%]", global->main->output.stream, global->main->context.set.title, alias_rule, global->main->context.set.title);
- fl_print_format("'.%c", global->main->output.stream, f_string_eol_s[0]);
+ fl_print_format("%c%s %s item rule ", global->main->output.stream, f_string_eol_s[0], entry_action->type == controller_entry_action_type_consider ? "Considering" : "Processing", is_entry ? controller_string_entry_s : controller_string_exit_s);
+ fl_print_format("'%[%Q%]'", global->main->output.stream, global->main->context.set.title, alias_rule, global->main->context.set.title);
+
+ if (entry->show == controller_entry_show_init && global->main->parameters[controller_parameter_simulate].result == f_console_result_none) {
+ fl_print_format(" [%[%s%]]", global->main->output.stream, global->main->context.set.notable, entry_action->code == controller_entry_rule_code_asynchronous ? controller_string_asynchronous_s : controller_string_synchronous_s, global->main->context.set.notable);
+
+ if (entry_action->code == controller_entry_rule_code_wait) {
+ fl_print_format(" [%[%s%]]", global->main->output.stream, global->main->context.set.notable, controller_string_wait_s, global->main->context.set.notable);
+ }
+
+ if (entry_action->code == controller_entry_rule_code_require) {
+ fl_print_format(" [%[%s%]]", global->main->output.stream, global->main->context.set.notable, controller_string_required_s, global->main->context.set.notable);
+ }
+ }
+
+ fl_print_format(".%c", global->main->output.stream, f_string_eol_s[0]);
controller_print_unlock_flush(global->main->output, global->thread);
}
}
}
else if (entry_action->type == controller_entry_action_type_execute) {
- if (global->main->parameters[controller_parameter_simulate].result == f_console_result_found || global->main->error.verbosity == f_console_verbosity_verbose) {
+ if (global->main->parameters[controller_parameter_simulate].result == f_console_result_found || global->main->error.verbosity == f_console_verbosity_verbose || entry->show == controller_entry_show_init) {
if (global->main->error.verbosity != f_console_verbosity_quiet) {
controller_print_lock(global->main->output, global->thread);
#ifndef _di_controller_entry_settings_read_
f_status_t controller_entry_settings_read(const bool is_entry, const f_string_range_t content_range, controller_global_t global, controller_cache_t *cache) {
+
f_status_t status = F_none;
{
f_array_length_t j = 0;
f_array_length_t line = 0;
+ controller_entry_t *entry = is_entry ? &global.setting->entry : &global.setting->exit;
+
for (; i < cache->object_actions.used; ++i) {
status = f_fss_count_lines(cache->buffer_file, cache->object_actions.array[i].start, &cache->action.line_action);
}
line = ++cache->action.line_action;
+ cache->action.name_action.used = 0;
status = controller_string_dynamic_rip_nulless_terminated(cache->buffer_file, cache->object_actions.array[i], &cache->action.name_action);
if (is_entry && fl_string_dynamic_compare_string(controller_string_mode_s, cache->action.name_action, controller_string_mode_length) == F_equal_to) {
if (cache->content_actions.array[i].used < 0 || cache->content_actions.array[i].used > 1) {
- if (global.main->error.verbosity != f_console_verbosity_quiet) {
- controller_print_lock(global.main->error.to, global.thread);
-
- fl_print_format("%c%[%SThe %s item setting '%]", global.main->error.to.stream, f_string_eol_s[0], global.main->error.context, global.main->error.prefix, is_entry ? controller_string_entry_s : controller_string_exit_s, global.main->error.context);
- fl_print_format("%[%Q%]", global.main->error.to.stream, global.main->error.notable, cache->action.name_action, global.main->error.notable);
- fl_print_format("%[' requires exactly %]", global.main->error.to.stream, global.main->error.context, global.main->error.context);
- fl_print_format("%[1%]", global.main->error.to.stream, global.main->error.notable, global.main->error.notable);
- fl_print_format("%[' parameter.%]%c", global.main->error.to.stream, global.main->error.context, global.main->error.context, f_string_eol_s[0]);
-
- controller_print_unlock_flush(global.main->error.to, global.thread);
- }
+ controller_entry_settings_read_print_setting_requires_exactly(is_entry, global, *cache, 1);
continue;
}
global.setting->mode = controller_setting_mode_program;
}
else {
- if (global.main->warning.verbosity == f_console_verbosity_debug) {
- controller_print_lock(global.main->warning.to, global.thread);
+ controller_entry_settings_read_print_setting_unknown_action_value(is_entry, global, *cache, i);
- fl_print_format("%c%[%Sfor %s item setting '%]", global.main->warning.to.stream, f_string_eol_s[0], global.main->warning.context, global.main->warning.prefix, is_entry ? controller_string_entry_s : controller_string_exit_s, global.main->warning.context);
- fl_print_format("%[%Q%]", global.main->warning.to.stream, global.main->warning.notable, cache->action.name_action, global.main->warning.notable);
- fl_print_format("%['.%]%c", global.main->warning.to.stream, global.main->warning.context, global.main->warning.context, f_string_eol_s[0]);
+ continue;
+ }
+ }
+ else if (fl_string_dynamic_compare_string(controller_string_pid_s, cache->action.name_action, controller_string_pid_length) == F_equal_to) {
+ if (cache->content_actions.array[i].used < 0 || cache->content_actions.array[i].used > 1) {
+ controller_entry_settings_read_print_setting_requires_exactly(is_entry, global, *cache, 1);
- controller_entry_error_print_cache(is_entry, global.main->warning, cache->action);
+ continue;
+ }
- controller_print_unlock_flush(global.main->warning.to, global.thread);
- }
+ if (fl_string_dynamic_partial_compare_string(controller_string_disable_s, cache->buffer_file, controller_string_disable_length, cache->content_actions.array[i].array[0]) == F_equal_to) {
+ entry->pid = controller_entry_pid_disable;
+ }
+ else if (fl_string_dynamic_partial_compare_string(controller_string_ready_s, cache->buffer_file, controller_string_ready_length, cache->content_actions.array[i].array[0]) == F_equal_to) {
+ entry->pid = controller_entry_pid_ready;
+ }
+ else if (fl_string_dynamic_partial_compare_string(controller_string_require_s, cache->buffer_file, controller_string_require_length, cache->content_actions.array[i].array[0]) == F_equal_to) {
+ entry->pid = controller_entry_pid_require;
+ }
+ else {
+ controller_entry_settings_read_print_setting_unknown_action_value(is_entry, global, *cache, i);
continue;
}
}
- else {
- if (global.main->warning.verbosity == f_console_verbosity_debug) {
- controller_print_lock(global.main->warning.to, global.thread);
+ else if (fl_string_dynamic_compare_string(controller_string_show_s, cache->action.name_action, controller_string_show_length) == F_equal_to) {
+ if (cache->content_actions.array[i].used < 0 || cache->content_actions.array[i].used > 1) {
+ controller_entry_settings_read_print_setting_requires_exactly(is_entry, global, *cache, 1);
- fl_print_format("%c%[%SUnknown %s item setting '%]", global.main->warning.to.stream, f_string_eol_s[0], global.main->warning.context, global.main->warning.prefix, is_entry ? controller_string_entry_s : controller_string_exit_s, global.main->warning.context);
- fl_print_format("%[%Q%]", global.main->warning.to.stream, global.main->warning.notable, cache->action.name_action, global.main->warning.notable);
- fl_print_format("%['.%]%c", global.main->warning.to.stream, global.main->warning.context, global.main->warning.context, f_string_eol_s[0]);
+ continue;
+ }
- controller_entry_error_print_cache(is_entry, global.main->warning, cache->action);
+ if (fl_string_dynamic_partial_compare_string(controller_string_normal_s, cache->buffer_file, controller_string_normal_length, cache->content_actions.array[i].array[0]) == F_equal_to) {
+ entry->show = controller_entry_show_normal;
+ }
+ else if (fl_string_dynamic_partial_compare_string(controller_string_init_s, cache->buffer_file, controller_string_init_length, cache->content_actions.array[i].array[0]) == F_equal_to) {
+ entry->show = controller_entry_show_init;
+ }
+ else {
+ controller_entry_settings_read_print_setting_unknown_action_value(is_entry, global, *cache, i);
- controller_print_unlock_flush(global.main->warning.to, global.thread);
+ continue;
+ }
+ }
+ else {
+ if (global.main->warning.verbosity == f_console_verbosity_debug) {
+ controller_entry_settings_read_print_setting_unknown_action(is_entry, global, *cache);
}
continue;
}
#endif // _di_controller_entry_settings_read_
+#ifndef _di_controller_entry_settings_read_print_setting_requires_exactly_
+ void controller_entry_settings_read_print_setting_requires_exactly(const bool is_entry, const controller_global_t global, const controller_cache_t cache, const f_number_unsigned_t total) {
+
+ if (global.main->error.verbosity == f_console_verbosity_quiet) return;
+
+ controller_print_lock(global.main->error.to, global.thread);
+
+ fl_print_format("%c%[%SThe %s item setting '%]", global.main->error.to.stream, f_string_eol_s[0], global.main->error.context, global.main->error.prefix, is_entry ? controller_string_entry_s : controller_string_exit_s, global.main->error.context);
+ fl_print_format("%[%Q%]", global.main->error.to.stream, global.main->error.notable, cache.action.name_action, global.main->error.notable);
+ fl_print_format("%[' requires exactly %]", global.main->error.to.stream, global.main->error.context, global.main->error.context);
+ fl_print_format("%[%un%]", global.main->error.to.stream, global.main->error.notable, total, global.main->error.notable);
+ fl_print_format("%[' %s.%]%c", global.main->error.to.stream, global.main->error.context, total > 1 ? controller_string_parameters_s : controller_string_parameter_s, global.main->error.context, f_string_eol_s[0]);
+
+ controller_entry_error_print_cache(is_entry, global.main->error, cache.action);
+
+ controller_print_unlock_flush(global.main->error.to, global.thread);
+ }
+#endif // _di_controller_entry_settings_read_print_setting_requires_exactly_
+
+#ifndef _di_controller_entry_settings_read_print_setting_unknown_action_
+ void controller_entry_settings_read_print_setting_unknown_action(const bool is_entry, const controller_global_t global, const controller_cache_t cache) {
+
+ if (global.main->warning.verbosity != f_console_verbosity_debug) return;
+
+ controller_print_lock(global.main->warning.to, global.thread);
+
+ fl_print_format("%c%[%SUnknown %s item setting '%]", global.main->warning.to.stream, f_string_eol_s[0], global.main->warning.context, global.main->warning.prefix, is_entry ? controller_string_entry_s : controller_string_exit_s, global.main->warning.context);
+ fl_print_format("%[%Q%]", global.main->warning.to.stream, global.main->warning.notable, cache.action.name_action, global.main->warning.notable);
+ fl_print_format("%['.%]%c", global.main->warning.to.stream, global.main->warning.context, global.main->warning.context, f_string_eol_s[0]);
+
+ controller_entry_error_print_cache(is_entry, global.main->warning, cache.action);
+
+ controller_print_unlock_flush(global.main->warning.to, global.thread);
+ }
+#endif // _di_controller_entry_settings_read_print_setting_unknown_action_
+
+#ifndef _di_controller_entry_settings_read_print_setting_unknown_action_value_
+ void controller_entry_settings_read_print_setting_unknown_action_value(const bool is_entry, const controller_global_t global, const controller_cache_t cache, const f_array_length_t index) {
+
+ if (global.main->warning.verbosity != f_console_verbosity_debug) return;
+
+ controller_print_lock(global.main->warning.to, global.thread);
+
+ fl_print_format("%c%[%SThe %s item setting '%]", global.main->warning.to.stream, f_string_eol_s[0], global.main->warning.context, global.main->warning.prefix, is_entry ? controller_string_entry_s : controller_string_exit_s, global.main->warning.context);
+ fl_print_format("%[%Q%]", global.main->warning.to.stream, global.main->warning.notable, cache.action.name_action, global.main->warning.notable);
+ fl_print_format("%[' has an unknown value '%]", global.main->warning.to.stream, f_string_eol_s[0], global.main->warning.context, global.main->warning.prefix, is_entry ? controller_string_entry_s : controller_string_exit_s, global.main->warning.context);
+ fl_print_format("%[%Q%]", global.main->warning.to.stream, global.main->warning.notable, cache.content_actions.array[index].array[0], global.main->warning.notable);
+ fl_print_format("%['.%]%c", global.main->warning.to.stream, global.main->warning.context, global.main->warning.context, f_string_eol_s[0]);
+
+ controller_entry_error_print_cache(is_entry, global.main->warning, cache.action);
+
+ controller_print_unlock_flush(global.main->warning.to, global.thread);
+ }
+#endif // _di_controller_entry_settings_read_print_setting_unknown_action_value_
+
#ifdef __cplusplus
} // extern "C"
#endif
extern f_status_t controller_entry_settings_read(const bool is_entry, const f_string_range_t content_range, controller_global_t global, controller_cache_t *cache) f_attribute_visibility_internal;
#endif // _di_controller_entry_settings_read_
+/**
+ * Print a message for when an entry setting action has the incorrect number of parameters.
+ *
+ * @param is_entry
+ * If TRUE, then this loads as an entry.
+ * If FALSE, then this loads as an exit.
+ * @param global
+ * The global data.
+ * @param cache
+ * A structure for containing and caching relevant data.
+ * @param total
+ * The expected number of arguments.
+ */
+#ifndef _di_controller_entry_settings_read_print_setting_requires_exactly_
+ extern void controller_entry_settings_read_print_setting_requires_exactly(const bool is_entry, const controller_global_t global, const controller_cache_t cache, const f_number_unsigned_t total) f_attribute_visibility_internal;
+#endif // _di_controller_entry_settings_read_print_setting_requires_exactly_
+
+/**
+ * Print a message for when an entry setting action is unknown.
+ *
+ * @param is_entry
+ * If TRUE, then this loads as an entry.
+ * If FALSE, then this loads as an exit.
+ * @param global
+ * The global data.
+ * @param cache
+ * A structure for containing and caching relevant data.
+ */
+#ifndef _di_controller_entry_settings_read_print_setting_unknown_action_
+ extern void controller_entry_settings_read_print_setting_unknown_action(const bool is_entry, const controller_global_t global, const controller_cache_t cache) f_attribute_visibility_internal;
+#endif // _di_controller_entry_settings_read_print_setting_unknown_action_
+
+/**
+ * Print a message for when an entry setting action has an unknown value.
+ *
+ * @param is_entry
+ * If TRUE, then this loads as an entry.
+ * If FALSE, then this loads as an exit.
+ * @param global
+ * The global data.
+ * @param cache
+ * A structure for containing and caching relevant data.
+ * @param total
+ * The expected number of arguments.
+ * @param index
+ * The location in the content actions array representing the action value.
+ */
+#ifndef _di_controller_entry_settings_read_print_setting_unknown_action_value_
+ extern void controller_entry_settings_read_print_setting_unknown_action_value(const bool is_entry, const controller_global_t global, const controller_cache_t cache, const f_array_length_t index) f_attribute_visibility_internal;
+#endif // _di_controller_entry_settings_read_print_setting_unknown_action_value_
+
#ifdef __cplusplus
} // extern "C"
#endif
fl_print_format("%cRule %[%Q%] {%c", main->output.stream, f_string_eol_s[0], main->context.set.title, rule.alias, main->context.set.title, f_string_eol_s[0]);
fl_print_format(" %[%s%] %Q%c", main->output.stream, main->context.set.important, controller_string_name_s, main->context.set.important, rule.name, f_string_eol_s[0]);
fl_print_format(" %[%s%] %s%c", main->output.stream, main->context.set.important, controller_string_how_s, main->context.set.important, options & controller_process_option_asynchronous ? controller_string_asynchronous_s : controller_string_synchronous_s, f_string_eol_s[0]);
- fl_print_format(" %[%s%] %s%c", main->output.stream, main->context.set.important, controller_string_wait_s, main->context.set.important, options & controller_process_option_wait ? controller_string_yes : controller_string_no_s, f_string_eol_s[0]);
+ fl_print_format(" %[%s%] %s%c", main->output.stream, main->context.set.important, controller_string_wait_s, main->context.set.important, options & controller_process_option_wait ? controller_string_yes_s : controller_string_no_s, f_string_eol_s[0]);
fl_print_format(" %[%s%] ", main->output.stream, main->context.set.important, controller_string_capability_s, main->context.set.important);
if (f_capability_supported()) {
if (F_status_is_error_not(*status) && *status != F_signal && *status != F_child) {
if (main->parameters[controller_parameter_validate].result == f_console_result_none || main->parameters[controller_parameter_simulate].result == f_console_result_found) {
- if (f_file_exists(entry->setting->path_pid.string) == F_true) {
+ if (entry->setting->entry.pid == controller_entry_pid_require && f_file_exists(entry->setting->path_pid.string) == F_true) {
if (main->error.verbosity != f_console_verbosity_quiet) {
controller_print_lock(main->error.to, entry->global->thread);
entry->setting->ready = controller_setting_ready_fail;
if ((F_status_set_fine(*status) == F_execute || F_status_set_fine(*status) == F_require) && entry->global->setting->failsafe_enabled) {
-
const uint8_t original_enabled = entry->global->thread->enabled;
// restore operating mode so that the failsafe can execute.
# A very basic boot process.
#
+setting:
+ pid ready
+ show init
+
main:
timeout start 7
timeout stop 7
console:
start service mouse asynchronous
- start program terminal require wait
+
+ start terminal two asynchronous
+ start terminal three asynchronous
+ start terminal four asynchronous
+ start terminal one require wait
+
maintenance:
+ #execute /bin/agetty -8 -i -J - linux
execute /bin/bash --login
# A boot to bash process.
#
+setting:
+ pid disable
+ show init
+
main:
- execute bash --login
+ #execute /bin/agetty -8 -i -J - linux
+ execute /bin/bash --login
command:
start swapon -a
stop swapoff -a
+
+script:
+ start {
+ if [[ ! -d /var/run/init ]] ; then
+ mkdir /var/run/init
+ fi
+ }
+++ /dev/null
-# fss-000d
-#
-# Rule for the terminal programs.
-#
-# -m = don't prompt for login.
-
-setting:
- name "System Terminals"
-
-command:
- start agetty -8 9600 tty2 linux
-
-command:
- start agetty -8 9600 tty3 linux
-
-command:
- start agetty -8 9600 tty4 linux
-
-# Wait for things to complete before opening the terminal on tty1.
-command:
- start sleep 3s
-
-command:
- start agetty -8 9600 tty1 linux
--- /dev/null
+# fss-000d
+#
+# Rule for the terminal programs.
+#
+# -m = don't prompt for login.
+# -J = don't clear on start, good for debugging.
+# 9600 and 115200 are common frequencies.
+
+setting:
+ name "System Terminal 4"
+
+command:
+ start agetty -8 tty4 linux
--- /dev/null
+# fss-000d
+#
+# Rule for the terminal programs.
+#
+# -m = don't prompt for login.
+# -J = don't clear on start, good for debugging.
+# 9600 and 115200 are common frequencies.
+
+setting:
+ name "System Terminal 1"
+
+command:
+ start agetty -8 -i -J - linux
--- /dev/null
+# fss-000d
+#
+# Rule for the terminal programs.
+#
+# -m = don't prompt for login.
+# -J = don't clear on start, good for debugging.
+# 9600 and 115200 are common frequencies.
+
+setting:
+ name "System Terminal 3"
+
+command:
+ start agetty -8 tty3 linux
--- /dev/null
+# fss-000d
+#
+# Rule for the terminal programs.
+#
+# -m = don't prompt for login.
+# -J = don't clear on start, good for debugging.
+# 9600 and 115200 are common frequencies.
+
+setting:
+ name "System Terminal 2"
+
+command:
+ start agetty -8 tty2 linux
The "setting" Item Object represents settings and is not an "item" that can be executed.
A number of settings are supported, but if this Item Object is not specified, then defaults are used.
- The following settings are available: "mode".
+ The following settings are available: "mode", "pid", and "show".
The "mode" setting represents the mode in which the Entry is operating in.
The following modes are supported: "program" and "service".
Does not support the Item Action "execute".
This is the default mode.
+ The "pid" setting represents how the entry pid file is generated or not.
+ The following modes are supported: "disable", "require", and "ready".
+ For "disable", not pid file representing the entry is created.
+ For "require", check to see if the PID file exists for an entry at startup and then when "ready" create a pid file, display error on pid file already exists or on failure and then fail.
+ For "ready", when "ready" create a pid file, display error on failure and then fail (does not check if PID file exists).
+
+ The "show" setting represents the way entry processing presents information to the screen.
+ This applies only to the entry and rule processing itself and does not handle the output of programs and scripts being executed by some entry or rule.
+ The following show options are supported: "normal" and "init".
+ For "normal", will not report the start or stop of some entry or rule execution but will report any errors or warnings as appropriate.
+ For "init", will report when starting programs and may include reporting success and failure status.
+
Each "item" supports the following Action Names: "consider", "execute", "failsafe", "freeze", "item", "kill", "pause", "reload", "restart", "ready", "resume", "start", "stop", and "timeout".
Of those types, the following are considered a "rule" Action: "freeze", "kill", "pause", "reload", "restart", "resume", "start", "stop", and "thaw".
The "setting" Item Object represents settings and is not an "item" that can be executed.
A number of settings are supported, but if this Item Object is not specified, then defaults are used.
- There are no settings are available.
+ The following settings are available: "pid" and "show".
- Each item supports the following Action Names: "consider", "failsafe", "freeze", "item", "kill", "pause", "reload", "restart", "ready", "resume", "start", "stop", and "timeout".
- Of those types, the following are considered a "rule" Action: "freeze", "kill", "pause", "reload", "restart", "resume", "start", and "stop".
+ The "pid" setting represents how the entry pid file is generated or not.
+ The following modes are supported: "disable", "require", and "ready".
+ For "disable", not pid file representing the entry is created.
+ For "require", check to see if the PID file exists for an entry at startup and then when "ready" create a pid file, display error on pid file already exists or on failure and then fail.
+ For "ready", when "ready" create a pid file, display error on failure and then fail (does not check if PID file exists).
- The "consider" Action is a special case of a "rule" Action.
+ The "show" setting represents the way entry processing presents information to the screen.
+ This applies only to the entry and rule processing itself and does not handle the output of programs and scripts being executed by some entry or rule.
+ The following show options are supported: "normal" and "init".
+ For "normal", will not report the start or stop of some entry or rule execution but will report any errors or warnings as appropriate.
+ For "init", will report when starting programs and may include reporting success and failure status.
+
+ Each "item" supports the following Action Names: "consider", "execute", "failsafe", "freeze", "item", "kill", "pause", "reload", "restart", "ready", "resume", "start", "stop", and "timeout".
+ Of those types, the following are considered a "rule" Action: "freeze", "kill", "pause", "reload", "restart", "resume", "start", "stop", and "thaw".
+
+ The "consider" Item Action is a special case of a "rule" Action.
All Action Parameters are the same as with the "rule" Action Parameters.
The difference is that "consider" is only processed (instead of being processed and executed) and when some "rule" Action designates that this consideration is required (via "need"), wanted (via "want"), or wished for (via "wish") from the within the Rule file.
If this is determined to be executed, then this is immediately executed when needed, wanted or wished for and applies all properties as appropriate (such as "asynchronous", for example).
If this is determined not to be executed, then this "consider" is ignored as if it was never there in the first place.
- The "failsafe" Action accepts only a valid Item Name in which will be executed when a failure is detected.
- Only a single "failsafe" Action may exist at a time.
- Each successive "failsafe" Action specified replaces the previously defined "failsafe" Action (in a top-down manner).
- When operating in "failsafe", the "require" Action is ignored given that it is meaningless once operating in failsafe.
+ The "execute" Item Action well execute into the specified program.
+ On successfull execution, the controller program will no longer be running and will be replaced with the designated program.
+ This Item Action is only supported when operating in "program" mode.
+
+ The "failsafe" Item Action accepts only a valid Item Name in which will be executed when a failure is detected.
+ Only a single "failsafe" Item Action may function at a time.
+ Each successive "failsafe" Item Action specified replaces the previously defined "failsafe" Item Action (in a top-down manner).
+ When operating in "failsafe", the "require" Item Action is ignored (given that it is meaningless once operating in "failsafe" mode).
- The "freeze" is a "rule" Action for freezing some Control Group.
- This "rule" Action will process the "freeze" inner Content of the named Rule.
+ The "freeze" Item Action is a "rule" Action for freezing some Control Group.
+ This Item Action will process the "freeze" inner Content of the named Rule.
This is specific to Control Groups and is not yet fully implemented.
Once implemented this documentation will need to be updated and clarified.
- The "item" Action accepts only a valid Item Name in which will be immediately executed.
+ The "item" Item Action accepts only a valid Item Name in which will be immediately executed.
Any valid Item Name, except for the reserved "main", may be used.
- The "kill" is a "rule" Action for forcibly terminating some process.
- This "rule" Action will process the "kill" inner Content of the named Rule.
+ The "kill" Item Action is a "rule" Action for forcibly terminating some process.
+ This Item Action will process the "kill" inner Content of the named Rule.
- The "pause" is a "rule" Action for pausing some process.
- This "rule" Action will process the "pause" inner Content of the named Rule.
+ The "pause" Item Action is a "rule" Action for pausing some process.
+ This Item Action will process the "pause" inner Content of the named Rule.
- The "reload" is a "rule" Action for pausing some process.
- This "rule" Action will process the "reload" inner Content of the named Rule.
+ The "reload" Item Action is a "rule" Action for pausing some process.
+ This Item Action will process the "reload" inner Content of the named Rule.
- The "restart" is a "rule" Action for pausing some process.
- This "rule" Action will process the "restart" inner Content of the named Rule.
+ The "restart" Item Action is a "rule" Action for pausing some process.
+ This Item Action will process the "restart" inner Content of the named Rule.
- The "resume" is a "rule" Action for pausing some process.
- This "rule" Action will process the "resume" inner Content of the named Rule.
+ The "resume" Item Action is a "rule" Action for pausing some process.
+ This Item Action will process the "resume" inner Content of the named Rule.
The "ready" Action instructs the controller program when it is safe to perform normal tasks, such as creating the pid file.
When not specified, the state is always assumed to be ready.
Adding "ready" essentially specifies a point in time in the Entry in which things are expected to be safe for such basic operations.
When the optional "wait" is provided, then "ready" will wait for all currently started asynchronous processes to complete before operating.
- The "start" is a "rule" Action for pausing some process.
- This "rule" Action will process the "start" inner Content of the named Rule.
+ The "start" Item Action is a "rule" Action for pausing some process.
+ This Item Action will process the "start" inner Content of the named Rule.
- The "stop" is a "rule" Action for pausing some process.
- This "rule" Action will process the "stop" inner Content of the named Rule.
+ The "stop" Item Action is a "rule" Action for pausing some process.
+ This Item Action will process the "stop" inner Content of the named Rule.
- The "thaw" is a "rule" Action for unfreezing some Control Group.
- This "rule" Action will process the "thaw" inner Content of the named Rule.
+ The "thaw" Item Action is a "rule" Action for unfreezing some Control Group.
+ This Item Action will process the "thaw" inner Content of the named Rule.
This is specific to Control Groups and is not yet fully implemented.
Once implemented this documentation will need to be updated and clarified.
- The "timeout" Action provides default global settings for each of the three special situations: "start", "stop", and "kill".
+ The "timeout" Item Action provides default global settings for each of the three special situations: "start", "stop", and "kill".
Each of these may only have a single one exist at a time (one "start", one "stop", and one "kill").
- Each successive "timeout" Action, specific to each Action Name (such as "start"), specified replaces the previously defined "timeout" Action (in a top-down manner).
+ Each successive "timeout" Item Action, specific to each Action Name (such as "start"), specified replaces the previously defined "timeout" Action (in a top-down manner).
Each of these accepts a single Action Parameter that is a 0 or greater whole number representing the number of MegaTime (MT) (equivalent to milliseconds).
For "start", this represents the number of MegaTime to wait after starting some rule before assuming something went wrong and the rule is returned as failed.
For "stop", this represents the number of MegaTime to wait after stopping some rule before assuming something went wrong and the rule is returned as failed.
The timeouts are generally only valid for services such as daemon services.
A value of 0 disables this (prevents any action).
-Entry Rule Documentation:
+Exit Rule Documentation:
There are multiple Entry Actions that are considered "rule" Actions.
These are: "freeze", "kill", "pause", "reload", "restart", "resume", "start", "stop", and "thaw".
"main": required.
"setting": optional, Actions may be one of:
- "mode": either "program" or "service".
+ - "pid": either "disable", "require", or "ready".
+ - "show": either "normal" or "init".
The Entry file may have any other valid Item Objects, but only the above are reserved.
The Items:
"main": required.
- "setting": optional, but not Actions are currently supported.
+ "setting": optional, Actions may be one of:
+ - "pid": either "disable", "optional", or "require".
+ - "show": either "normal" or "init".
The Exit file may have any other valid Item Objects, but only the above are reserved.