From: Kevin Day Date: Fri, 16 Apr 2021 04:20:22 +0000 (-0500) Subject: Progress: controller program, begin working on pid file related executions. X-Git-Tag: 0.5.3~42 X-Git-Url: https://git.kevux.org/?a=commitdiff_plain;h=daa284c3219419d7b718167f84386b2e9a44cae8;p=fll Progress: controller program, begin working on pid file related executions. It occurred to me that I could quickly create a process with a PID file using a script. I then realized that "service" only applies to binaries and not scripts. Add a new type called "utility" that is identical to "service" in purpose except that it processes scripts. Begin implementing the PID file related code. It seems there are a few things to address, such as proper test output display. For example, I am seeing "Simulating execution of '/var/run/sshd.pid' with the arguments: '' from 'SSH Service'.". That "/var/run/sshd.pid" should instead be "/usr/sbin/sshd". Creating or checking existence of the PID files is not yet written. The behavior of after a process forks is not yet written either. An error needs to be printed and F_failure (with error bit set) should be returned. The "success = F_failure" should probably have error bit set. Add new rules and entries for testing this (to be implemented) functionality. Update the documentation. Some of the documentation is outdated and as a result, wrong. --- diff --git a/level_3/controller/c/private-common.h b/level_3/controller/c/private-common.h index 5919378..9d27729 100644 --- a/level_3/controller/c/private-common.h +++ b/level_3/controller/c/private-common.h @@ -100,6 +100,7 @@ extern "C" { #define controller_string_type "type" #define controller_string_use "use" #define controller_string_user "user" + #define controller_string_utility "utility" #define controller_string_wait "wait" #define controller_string_want "want" #define controller_string_wish "wish" @@ -186,6 +187,7 @@ extern "C" { #define controller_string_type_length 4 #define controller_string_use_length 3 #define controller_string_user_length 4 + #define controller_string_utility_length 7 #define controller_string_wait_length 4 #define controller_string_want_length 4 #define controller_string_wish_length 4 @@ -273,6 +275,7 @@ extern "C" { const static f_string_t controller_string_type_s = controller_string_type; const static f_string_t controller_string_use_s = controller_string_use; const static f_string_t controller_string_user_s = controller_string_user; + const static f_string_t controller_string_utility_s = controller_string_utility; const static f_string_t controller_string_wait_s = controller_string_wait; const static f_string_t controller_string_want_s = controller_string_want; const static f_string_t controller_string_wish_s = controller_string_wish; @@ -544,6 +547,7 @@ extern "C" { controller_rule_item_type_script, controller_rule_item_type_service, controller_rule_item_type_setting, + controller_rule_item_type_utility, }; typedef struct { diff --git a/level_3/controller/c/private-rule.c b/level_3/controller/c/private-rule.c index e01e806..d15789f 100644 --- a/level_3/controller/c/private-rule.c +++ b/level_3/controller/c/private-rule.c @@ -236,8 +236,8 @@ extern "C" { } else { - // "script" types use the entire content and can be directly passed through. - if (item->type == controller_rule_item_type_script) { + // "script" and "utility" types use the entire content and can be directly passed through. + if (item->type == controller_rule_item_type_script || item->type == controller_rule_item_type_utility) { actions->array[actions->used].parameters.used = 0; status = f_string_dynamics_increase(&actions->array[actions->used].parameters); @@ -350,7 +350,7 @@ extern "C" { if (F_status_is_error(status)) { controller_error_print(main.data->error, F_status_set_fine(status), "fl_fss_apply_delimit", F_true, main.thread); } - else if (item->type == controller_rule_item_type_script) { + else if (item->type == controller_rule_item_type_script || item->type == controller_rule_item_type_utility) { status = f_string_dynamics_increase(&actions->array[actions->used].parameters); if (F_status_is_error(status)) { @@ -743,6 +743,18 @@ extern "C" { } #endif // _di_controller_rule_item_error_print_rule_not_loaded_ +#ifndef _di_controller_rule_action_error_missing_pid_ + void controller_rule_action_error_missing_pid(const fll_error_print_t print, const f_string_t alias) { + + if (print.verbosity != f_console_verbosity_quiet) { + fprintf(print.to.stream, "%c", f_string_eol_s[0]); + fprintf(print.to.stream, "%s%sThe rule '", print.context.before->string, print.prefix ? print.prefix : f_string_empty_s); + fprintf(print.to.stream, "%s%s%s%s", print.context.after->string, print.notable.before->string, alias, print.notable.after->string); + fprintf(print.to.stream, "%s' is not designating a pid file.%s%c", print.context.before->string, print.context.after->string, f_string_eol_s[0]); + } + } +#endif // _di_controller_rule_action_error_missing_pid_ + #ifndef _di_controller_rule_execute_ f_status_t controller_rule_execute(const uint8_t action, const uint8_t options, const controller_main_t main, controller_process_t *process) { @@ -753,6 +765,9 @@ extern "C" { f_array_length_t j = 0; f_array_length_t k = 0; + f_string_dynamic_t *pid_file = 0; + uint8_t pid_type = 0; + // child processes should receive all signals and handle the signals as they see fit. f_signal_how_t signals = f_signal_how_t_initialize; f_signal_set_empty(&signals.block); @@ -850,7 +865,7 @@ extern "C" { if (!(options & controller_process_option_simulate)) break; - success = F_failure; + success = F_status_set_error(F_failure); } else if (success == F_false || success == F_ignore) { success = F_true; @@ -881,23 +896,96 @@ extern "C" { } else if (process->rule.items.array[i].type == controller_rule_item_type_service) { - if (strchr(process->rule.items.array[i].actions.array[j].parameters.array[0].string, f_path_separator_s[0])) { - execute_set.parameter.option |= fl_execute_parameter_option_path; + pid_file = 0; + pid_type = 0; + + for (k = 0; k < process->rule.items.array[i].actions.used; ++k) { + + if (process->rule.items.array[i].actions.array[k].type != controller_rule_action_type_create && process->rule.items.array[i].actions.array[k].type != controller_rule_action_type_use) { + continue; + } + + if (!process->rule.items.array[i].actions.array[k].parameters.used) { + continue; + } + + pid_file = &process->rule.items.array[i].actions.array[k].parameters.array[0]; + pid_type = process->rule.items.array[i].actions.array[k].type; + } // for + + if (pid_file) { + if (strchr(process->rule.items.array[i].actions.array[j].parameters.array[0].string, f_path_separator_s[0])) { + execute_set.parameter.option |= fl_execute_parameter_option_path; + } + + status = controller_rule_execute_pid_with(pid_file, pid_type, process->rule.items.array[i].type, process->rule.items.array[i].actions.array[j], 0, process->rule.items.array[i].actions.array[j].parameters, options, main, &execute_set, process); + + if (status == F_child || status == F_signal || F_status_set_fine(status) == F_lock) break; + + if (F_status_is_error(status)) { + process->rule.items.array[i].actions.array[j].status = F_status_set_error(F_failure); + + if (!(options & controller_process_option_simulate)) break; + + success = F_status_set_error(F_failure); + } + else if (success == F_false || success == F_ignore) { + success = F_true; + } } + else { + success = F_status_set_error(F_failure); - status = controller_rule_execute_pid_with(process->rule.items.array[i].type, process->rule.items.array[i].actions.array[j], 0, process->rule.items.array[i].actions.array[j].parameters, options, main, &execute_set, process); + // @todo make this more specific. + controller_rule_action_error_missing_pid(main.data->error, process->rule.alias.string); + } + } + else if (process->rule.items.array[i].type == controller_rule_item_type_utility) { - if (status == F_child || status == F_signal || F_status_set_fine(status) == F_lock) break; + pid_file = 0; + pid_type = 0; - if (F_status_is_error(status)) { - process->rule.items.array[i].actions.array[j].status = F_status_set_error(F_failure); + for (k = 0; k < process->rule.items.array[i].actions.used; ++k) { - if (!(options & controller_process_option_simulate)) break; + if (process->rule.items.array[i].actions.array[k].type != controller_rule_action_type_create && process->rule.items.array[i].actions.array[k].type != controller_rule_action_type_use) { + continue; + } + + if (!process->rule.items.array[i].actions.array[k].parameters.used) { + continue; + } + + pid_file = &process->rule.items.array[i].actions.array[k].parameters.array[0]; + pid_type = process->rule.items.array[i].actions.array[k].type; + } // for - success = F_failure; + if (pid_file) { + execute_set.parameter.data = &process->rule.items.array[i].actions.array[j].parameters.array[0]; + + if (process->rule.script.used && strchr(process->rule.script.string, f_path_separator_s[0])) { + execute_set.parameter.option |= fl_execute_parameter_option_path; + } + + status = controller_rule_execute_pid_with(pid_file, pid_type, process->rule.items.array[i].type, process->rule.items.array[i].actions.array[j], process->rule.script.used ? process->rule.script.string : controller_default_program_script, arguments_none, options, main, &execute_set, process); + + if (status == F_child || status == F_signal || F_status_set_fine(status) == F_lock) break; + + if (F_status_is_error(status)) { + process->rule.items.array[i].actions.array[j].status = F_status_set_error(F_failure); + + if (!(options & controller_process_option_simulate)) break; + + success = F_status_set_error(F_failure); + } + else if (success == F_false || success == F_ignore) { + success = F_true; + } } - else if (success == F_false || success == F_ignore) { - success = F_true; + else { + success = F_status_set_error(F_failure); + + // @todo make this more specific. + controller_rule_action_error_missing_pid(main.data->error, process->rule.alias.string); } } else { @@ -946,7 +1034,7 @@ extern "C" { } if (success == F_false || success == F_failure) { - return F_failure; + return F_status_set_error(F_failure); } if (success == F_ignore) { @@ -1126,7 +1214,7 @@ extern "C" { #endif // _di_controller_rule_execute_foreground_ #ifndef _di_controller_rule_execute_pid_with_ - f_status_t controller_rule_execute_pid_with(const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, const controller_main_t main, controller_execute_set_t * const execute_set, controller_process_t *process) { + f_status_t controller_rule_execute_pid_with(const f_string_dynamic_t *pid_file, const uint8_t pid_type, const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, const controller_main_t main, controller_execute_set_t * const execute_set, controller_process_t *process) { f_status_t status = F_none; f_status_t status_lock = F_none; @@ -1136,15 +1224,9 @@ extern "C" { // @todo check to see if pid file exists. - // @todo this needs to support/use an option to designate that the process automatically forks in the background. - // in which case fll_execute_program() is called. - // otherwise this needs to call an asynchronous execute process. - // until then, this controller_rule_execute_pid_with() function is not correct and only represents a process that forks to the background. - if (options & controller_process_option_simulate) { if (main.data->error.verbosity != f_console_verbosity_quiet) { - f_thread_mutex_lock(&main.thread->lock.print); fprintf(main.data->output.stream, "%c", f_string_eol_s[0]); @@ -1209,10 +1291,6 @@ extern "C" { // have the parent wait for the child process to finish. @todo do not wait, this is a background execution! instead, wait for pid file or timeout (or perhaps optional create the pid file). waitpid(id_child, &result, 0); - if (status_lock == F_none) { - f_thread_unlock(&process->lock); - } - if (!main.thread->enabled) { if (status_lock == F_none) { return F_signal; @@ -1221,6 +1299,10 @@ extern "C" { return F_signal; } + if (status_lock == F_none) { + f_thread_unlock(&process->lock); + } + status_lock = controller_lock_write(main.thread, &process->lock); if (status_lock == F_signal || F_status_is_error(status_lock)) { controller_lock_error_critical_print(main.data->error, F_status_set_fine(status_lock), F_false, main.thread); @@ -1284,7 +1366,7 @@ extern "C" { f_thread_mutex_lock(&main.thread->lock.print); if (status == F_control_group || status == F_failure || status == F_limit || status == F_processor || status == F_schedule) { - controller_rule_item_error_print_execute(main.data->error, type == controller_rule_item_type_script, program ? program : arguments.used ? arguments.array[0].string : f_string_empty_s, result, status); + controller_rule_item_error_print_execute(main.data->error, type == controller_rule_item_type_utility, program ? program : arguments.used ? arguments.array[0].string : f_string_empty_s, result, status); } else if (status == F_file_found_not) { controller_rule_item_error_print_execute_not_found(main.data->error, F_false, program); @@ -1529,6 +1611,11 @@ extern "C" { buffer.string = controller_string_setting_s; buffer.used = controller_string_setting_length; break; + + case controller_rule_item_type_utility: + buffer.string = controller_string_utility_s; + buffer.used = controller_string_utility_length; + break; } buffer.size = buffer.used; @@ -2798,6 +2885,9 @@ extern "C" { else if (fl_string_dynamic_compare_string(controller_string_service_s, cache->action.name_item, controller_string_service_length) == F_equal_to) { rule->items.array[rule->items.used].type = controller_rule_item_type_service; } + else if (fl_string_dynamic_compare_string(controller_string_utility_s, cache->action.name_item, controller_string_utility_length) == F_equal_to) { + rule->items.array[rule->items.used].type = controller_rule_item_type_utility; + } else { if (main.data->warning.verbosity == f_console_verbosity_debug) { f_thread_mutex_lock(&main.thread->lock.print); @@ -4907,7 +4997,7 @@ extern "C" { fprintf(data->output.stream, " %s%s%s {%c", data->context.set.important.before->string, controller_string_action_s, data->context.set.important.after->string, f_string_eol_s[0]); fprintf(data->output.stream, " %s%s%s %s%c", data->context.set.important.before->string, controller_string_type_s, data->context.set.important.after->string, controller_rule_action_type_name(action->type).string, f_string_eol_s[0]); - if (item->type == controller_rule_item_type_script) { + if (item->type == controller_rule_item_type_script || item->type == controller_rule_item_type_utility) { fprintf(data->output.stream, " %s%s%s {%c", data->context.set.important.before->string, controller_string_parameter_s, data->context.set.important.after->string, f_string_eol_s[0]); parameter = &action->parameters.array[0]; diff --git a/level_3/controller/c/private-rule.h b/level_3/controller/c/private-rule.h index 931875e..f32b12c 100644 --- a/level_3/controller/c/private-rule.h +++ b/level_3/controller/c/private-rule.h @@ -321,6 +321,18 @@ extern "C" { #endif // _di_controller_rule_item_error_print_rule_not_loaded_ /** + * Print an error or warning message about some rule not having the pid file information. + * + * @param print + * The error or warning output structure. + * @param alias + * The rule alias of the rule that is missing the pid file designation. + */ +#ifndef _di_controller_rule_action_error_missing_pid_ + extern void controller_rule_action_error_missing_pid(const fll_error_print_t print, const f_string_t alias) f_gcc_attribute_visibility_internal; +#endif // _di_controller_rule_action_error_missing_pid_ + +/** * Perform an execution of the given rule. * * This requires that a read lock be set on process->lock before being called. @@ -348,7 +360,9 @@ extern "C" { * F_none on success. * F_child on child process exiting. * F_signal on (exit) signal received. + * F_ignore if the rule is unknown and nothing can be done. * + * F_failure (with error bit) if failed to execute. * F_lock (with error bit) if failed to re-establish read lock on process->lock while returning. * * On success and the rule is run synchronously, then the individual status for the rule is set to F_complete. @@ -412,6 +426,10 @@ extern "C" { * When this is synchronous, this will wait for the PID file to be generated before continuing. * When this is asynchronous, this will continue on adding the rule id and action to the asynchronous list. * + * @param pid_file + * The path to the PID file. + * @param pid_type + * The type of the PID file, either "controller_rule_action_type_create" or "controller_rule_action_type_use". * @param type * The item type code. * @param action @@ -450,7 +468,7 @@ extern "C" { * @see fll_execute_program() */ #ifndef _di_controller_rule_execute_pid_with_ - extern f_status_t controller_rule_execute_pid_with(const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, const controller_main_t main, controller_execute_set_t * const execute_set, controller_process_t *process) f_gcc_attribute_visibility_internal; + extern f_status_t controller_rule_execute_pid_with(const f_string_dynamic_t *pid_file, const uint8_t pid_type, const uint8_t type, const controller_rule_action_t action, const f_string_t program, const f_string_dynamics_t arguments, const uint8_t options, const controller_main_t main, controller_execute_set_t * const execute_set, controller_process_t *process) f_gcc_attribute_visibility_internal; #endif // _di_controller_rule_execute_pid_with_ /** diff --git a/level_3/controller/data/settings/example/entries/sshd.entry b/level_3/controller/data/settings/example/entries/sshd.entry new file mode 100644 index 0000000..73a5a09 --- /dev/null +++ b/level_3/controller/data/settings/example/entries/sshd.entry @@ -0,0 +1,13 @@ +# fss-0005 + +main: + timeout start 7 + timeout stop 7 + timeout kill 3 + + failsafe boom + + rule service sshd + +boom: + rule maintenance explode diff --git a/level_3/controller/data/settings/example/entries/utility.entry b/level_3/controller/data/settings/example/entries/utility.entry new file mode 100644 index 0000000..b25a3b0 --- /dev/null +++ b/level_3/controller/data/settings/example/entries/utility.entry @@ -0,0 +1,14 @@ +# fss-0005 + +main: + timeout start 7 + timeout stop 7 + timeout kill 3 + + failsafe boom + + rule utility sleeper_1 + rule utility sleeper_2 + +boom: + rule maintenance explode diff --git a/level_3/controller/data/settings/example/rules/service/sshd.rule b/level_3/controller/data/settings/example/rules/service/sshd.rule new file mode 100644 index 0000000..71d8122 --- /dev/null +++ b/level_3/controller/data/settings/example/rules/service/sshd.rule @@ -0,0 +1,13 @@ +# fss-000d +# +# Example using the common sshd service. +# Sshd appears to require a full path. +# + +setting: + name "SSH Service" + nice 15 + +service: + use /var/run/sshd.pid + start /var/run/sshd.pid diff --git a/level_3/controller/data/settings/example/rules/utility/sleeper_1.rule b/level_3/controller/data/settings/example/rules/utility/sleeper_1.rule new file mode 100644 index 0000000..d68a12c --- /dev/null +++ b/level_3/controller/data/settings/example/rules/utility/sleeper_1.rule @@ -0,0 +1,30 @@ +# fss-000d +# sleeper rule whose program creates its own PID file, sleep for a while, removes PID file, and returns. + +setting: + name "Sleeper #1" + nice 10 + +utility: + use /tmp/sleeper_1.pid + start { + \#!/bin/bash + + main() { + if [[ -f /tmp/sleeper_1.pid ]] ; then + echo "Failure: pid file '/tmp/sleeper_1.pid' already exists." + return 1 + fi + + echo "$$" > /tmp/sleeper_1.pid + + echo "Sleeper 1, now sleeping." + sleep 20m + + echo "Sleeper 1, done sleeping." + rm -f /tmp/sleeper_1.pid + return 0 + \} + + main + } diff --git a/level_3/controller/data/settings/example/rules/utility/sleeper_2.rule b/level_3/controller/data/settings/example/rules/utility/sleeper_2.rule new file mode 100644 index 0000000..7eb1cae --- /dev/null +++ b/level_3/controller/data/settings/example/rules/utility/sleeper_2.rule @@ -0,0 +1,22 @@ +# fss-000d +# sleeper rule whose program does not create its own PID file, sleeps for a while and returns. + +setting: + name "Sleeper #2" + nice 10 + +utility: + create /tmp/sleeper_2.pid + start { + \#!/bin/bash + + main() { + echo "Sleeper 2, now sleeping." + sleep 25m + + echo "Sleeper 2, done sleeping." + return 0 + \} + + main + } diff --git a/level_3/controller/documents/rule.txt b/level_3/controller/documents/rule.txt index f51adad..b0bf63e 100644 --- a/level_3/controller/documents/rule.txt +++ b/level_3/controller/documents/rule.txt @@ -56,11 +56,12 @@ Rule Documentation: Supported non-real-time schedulers are: "batch", "idle", and "other" (aka: normal/default). Supported real-time schedulers are: "deadline", "fifo", "round_robin". + There are four available Rule Types to choose from: "command", "service", "script", and "utility". + The "command" Rule Type provides a simple command to run under the different circumstances: "start", "stop", "restart", and "reload". A "command" always operates in the foreground. The "service" Rule Type provides a "command" accompanied with a PID file (Process Identifier file). - Unlike the "command", a "service" always operates in the background. The "script" Rule Type provides a series of lines to be executed by a (Bash) script. This "script" operates in the foreground, but individual things done within the script may operate in foreground or background. @@ -69,6 +70,8 @@ Rule Documentation: A "script" is assumed to be in GNU Bash, which is the default expected behavior, but the specification does not explicitly require this. Another scripting language can be used but changing this incurs the responsibility to ensure all rules are updated to the appropriate scripting language. + The "utility" Rule Type provides a "script" accompanied with a PID file (Process Identifier file). + There are seven primary inner Content to perform: "kill", "pause", "restart", "resume", "reload", "start", and "stop". The "kill" Content is performed whenever this rule is executed using the kill action (which is, in general, a forced stop). @@ -83,6 +86,6 @@ Rule Documentation: When "reload", "start", or "stop" Content are not provided, then no respective action is performed. Commands are conditionally available depending on the presence of these, such as if "stop" is not provided then "stop" (and "restart") will not be available for the "control" program(s) to use. - The "create" Content designates that this controller program to create the PID file after successfully starting the service. - The "use" Content designates that the called program will provide the PID file after successfully starting the service. - For both "create" and "program" the PID file is expected to only exist on success or failure and the existence thereof designates the success or failure rate. + The "create" Content designates that this controller program to create the PID file after successfully starting a Service or Utility. + The "use" Content designates that the called program will provide the PID file after successfully starting the Service or Utility. + For both "create" and "program" the PID file is expected to only exist on success and the existence thereof designates the success or failure. diff --git a/level_3/controller/documents/simulate.txt b/level_3/controller/documents/simulate.txt index 5a45319..87c5265 100644 --- a/level_3/controller/documents/simulate.txt +++ b/level_3/controller/documents/simulate.txt @@ -6,19 +6,18 @@ Simulate Documentation: The "controller" program is design to support being run as an alternative to an init program (such as Sysvinit or SystemD). To help prevent problems, testing and simulation functionality is provided. - The "test" functionality, by itself will simply check the syntax of the Entry and Rule files (for Rule files specified in the Entry file). + The "validate" functionality, by itself will simply check the syntax of the Entry and Rule files (for Rule files specified in the Entry file). Errors are reported and nothing is executed. + The "controller" program will return 0 on validation success and 1 on validation failure. - The "test" functionality, when specified along with the "simulate" functionality, will perform just like the "test" functionality without the "simulate" except that additional information of the Rules to be executed will be printed. - There will be no execution or simulated execution of any Rule when both "test" and "simulate" are used togethor. - - The "simulate" functionality, by itself will perform a simulated execution of all Rules designated by the Entry file. - The simulation is not a true simulation in that no program is ever called to pretend to perform any operations. + The "test" functionality, by itself will perform a simulated execution of all Rules designated by an Entry file. + The simulation is not a true simulation in that no program is ever called to perform any operations. Furthermore, any "script" specified inside a Rule is only simulated as a whole and not its individual parts. + Once the Entry file is finished executing, the "test" will continue to run waiting on "control" commands. + + The "test" functionality, when specified along with the "validate" functionality, will perform similar to "validate" functionality except that additional information of the Rules to be executed will be printed. + There will be neither execution nor simulated execution of any Rule when both "test" and "validate" are used togethor. When a Rule is simulated, an empty script command (generally defaulting to "bash") is executed in place of the actual program being executed for each program or script in the Rule file that is to be executed. This allows for testing the designated permissions and other settings that would be applied when calling some program. - At this time, any Control Groups are not simulated but are actually created and the simulating process will actually be placed within the Control Group. - (@todo consider adding an additional parameter optionally to disable this behavior and ignore Control Groups during simulation.) - - (@todo both "test" and "simulate" functionality will need to consider being supported for testing individual Rules when requested by some "control" program.) + Control Groups are not simulated but are actually created and the simulating process will actually be placed within the Control Group. diff --git a/level_3/controller/specifications/rule.txt b/level_3/controller/specifications/rule.txt index 4713a38..63b19c6 100644 --- a/level_3/controller/specifications/rule.txt +++ b/level_3/controller/specifications/rule.txt @@ -22,6 +22,7 @@ Rule Specification: "script": FSS-0003 (Extended List) or FSS-0001 (Extended). "service": FSS-0003 (Extended List) or FSS-0001 (Extended). "settings": (Required) FSS-0001 (Extended). + "utility": FSS-0003 (Extended List) or FSS-0001 (Extended). For the above Rule Types, "settings" may be specified only once whereas the others may be specifed multiple times. The "settings" Rule Type is always processed first, regardless of position. @@ -46,38 +47,33 @@ Rule Specification: "want": Two Content, the first being a partial path and the second being a rule file name without extension (such as "boot" "modules"). "wish": Two Content, the first being a partial path and the second being a rule file name without extension (such as "boot" "modules"). - The "service" Rule Type allows the following the FSS-0001 (Extended)\: + The "service" and "utility" Rule Types allow the following the FSS-0001 (Extended)\: "create": One Content representing the path to a PID file. - "kill": One or more Content representing a program being executed and its arguments. - "restart": One or more Content representing a program being executed and its arguments. - "reload": One or more Content representing a program being executed and its arguments. - "start": One or more Content representing a program being executed and its arguments. - "stop": One or more Content representing a program being executed and its arguments. "use": One Content representing the path to a PID file. The "command" and "script" Rule Types allow the following the FSS-0001 (Extended)\: "kill": One or more Content representing a program being executed and its arguments. "pause": One or more Content representing a program being executed and its arguments. - "resume": One or more Content representing a program being executed and its arguments. - "restart": One or more Content representing a program being executed and its arguments. "reload": One or more Content representing a program being executed and its arguments. + "restart": One or more Content representing a program being executed and its arguments. + "resume": One or more Content representing a program being executed and its arguments. "start": One or more Content representing a program being executed and its arguments. "stop": One or more Content representing a program being executed and its arguments. The "command" and "service" Rule Types allow the following the FSS-0003 (Extended List)\: "kill": A list repesenting multiple programs and their respective arguments to execute. "pause": A list repesenting multiple programs and their respective arguments to execute. - "resume": A list repesenting multiple programs and their respective arguments to execute. - "restart": A list repesenting multiple programs and their respective arguments to execute. "reload": A list repesenting multiple programs and their respective arguments to execute. + "restart": A list repesenting multiple programs and their respective arguments to execute. + "resume": A list repesenting multiple programs and their respective arguments to execute. "start": A list repesenting multiple programs and their respective arguments to execute. "stop": A list repesenting multiple programs and their respective arguments to execute. - The "script" Rule Types allow the following the FSS-0003 (Extended List)\: - "kill": A list repesenting the contents of a (Bash) shell script. - "pause": A list repesenting the contents of a (Bash) shell script. - "resume": A list repesenting the contents of a (Bash) shell script. - "restart": A list repesenting the contents of a (Bash) shell script. - "reload": A list repesenting the contents of a (Bash) shell script. - "start": A list repesenting the contents of a (Bash) shell script. - "stop": A list repesenting the contents of a (Bash) shell script. + The "script" and "utility" Rule Types allow the following the FSS-0003 (Extended List)\: + "kill": A list repesenting the contents of a script, such as a GNU Bash shell. + "pause": A list repesenting the contents of a script, such as a GNU Bash shell. + "reload": A list repesenting the contents of a script, such as a GNU Bash shell. + "restart": A list repesenting the contents of a script, such as a GNU Bash shell. + "resume": A list repesenting the contents of a script, such as a GNU Bash shell. + "start": A list repesenting the contents of a script, such as a GNU Bash shell. + "stop": A list repesenting the contents of a script, such as a GNU Bash shell.