Minor tweaks.
Add new parameters and rule settings.
fll_program_print_help_option(output, context, f_console_standard_short_debug, f_console_standard_long_debug, f_console_symbol_short_disable, f_console_symbol_long_disable, " Enable debugging, inceasing verbosity beyond normal output.");
fll_program_print_help_option(output, context, f_console_standard_short_version, f_console_standard_long_version, f_console_symbol_short_disable, f_console_symbol_long_disable, " Print only the version number.");
+ fprintf(output.stream, "%c", f_string_eol[0]);
+
+ fll_program_print_help_option(output, context, controller_short_interruptable, controller_long_interruptable, f_console_symbol_short_enable, f_console_symbol_long_enable, " Designate that this program can be interrupted.");
+ fll_program_print_help_option(output, context, controller_short_settings, controller_long_settings, f_console_symbol_short_enable, f_console_symbol_long_enable, " Specify a custom settings path.");
+
fll_program_print_help_usage(output, context, controller_name, "");
return F_none;
} // for
f_macro_string_lengths_t_delete_simple(data->remaining);
-
f_macro_color_context_t_delete_simple(data->context);
return F_none;
* This program utilizes the Featureless Linux Library.
* This program provides system service management, much like sysvcontroller and controllerng.
* This program can be controlled from user-space via the "control" program.
+ *
+ * @todo research containers and build in container support into this, providing "container" appropriate verbiage for individual rules.
*/
#ifndef _controller_h
// libc includes
+#include <string.h>
// fll-0 includes
#include <level_0/type.h>
#ifndef _di_controller_defines_
#define controller_string_create "create"
#define controller_string_command "command"
+ #define controller_string_consider "consider"
#define controller_string_define "define"
+ #define controller_string_entry "entry"
+ #define controller_string_entries "entries"
#define controller_string_environment "environment"
#define controller_string_group "group"
#define controller_string_name "name"
#define controller_string_pid "pid"
#define controller_string_restart "restart"
#define controller_string_reload "reload"
+ #define controller_string_rule "rule"
+ #define controller_string_rules "rules"
#define controller_string_script "script"
#define controller_string_service "service"
#define controller_string_settings "settings"
#define controller_string_create_length 6
#define controller_string_command_length 7
+ #define controller_string_consider_length 8
#define controller_string_define_length 6
+ #define controller_string_entry_length 5
+ #define controller_string_entries_length 7
#define controller_string_environment_length 11
#define controller_string_group_length 5
#define controller_string_name_length 4
#define controller_string_pid_length 3
#define controller_string_restart_length 7
#define controller_string_reload_length 6
+ #define controller_string_rule_length 4
+ #define controller_string_rules_length 5
#define controller_string_script_length 6
#define controller_string_service_length 7
#define controller_string_settings_length 8
#define controller_string_use_length 3
#define controller_string_user_length 4
+ #define controller_path_settings "/etc/controller"
+
+ #define controller_path_settings_length 15
+
+ #define controller_short_interruptable "i"
+ #define controller_short_settings "s"
+
+ #define controller_long_interruptable "interruptable"
+ #define controller_long_settings "settings"
+
enum {
controller_parameter_help,
controller_parameter_light,
controller_parameter_verbosity_verbose,
controller_parameter_verbosity_debug,
controller_parameter_version,
+
+ controller_parameter_interruptable,
+ controller_parameter_settings,
};
#define controller_console_parameter_t_initialize \
f_console_parameter_t_initialize(f_console_standard_short_verbose, f_console_standard_long_verbose, 0, 0, f_console_type_inverse), \
f_console_parameter_t_initialize(f_console_standard_short_debug, f_console_standard_long_debug, 0, 0, f_console_type_inverse), \
f_console_parameter_t_initialize(f_console_standard_short_version, f_console_standard_long_version, 0, 0, f_console_type_inverse), \
+ f_console_parameter_t_initialize(controller_short_interruptable, controller_long_interruptable, 0, 0, f_console_type_normal), \
+ f_console_parameter_t_initialize(controller_short_settings, controller_long_settings, 0, 1, f_console_type_normal), \
}
- #define controller_total_parameters 9
+ #define controller_total_parameters 11
#endif // _di_controller_defines_
-#ifndef _di_controller_data_t_
- typedef struct {
- f_console_parameter_t parameters[controller_total_parameters];
-
- f_string_lengths_t remaining;
- bool process_pipe;
-
- f_file_t output;
- fll_error_print_t error;
- fll_error_print_t warning;
-
- f_color_context_t context;
- } controller_data_t;
-
- #define controller_data_initialize \
- { \
- controller_console_parameter_t_initialize, \
- f_string_lengths_t_initialize, \
- F_false, \
- f_macro_file_t_initialize(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
- fll_error_print_t_initialize, \
- fll_macro_error_print_t_initialize_warning(), \
- f_color_context_t_initialize, \
- }
-#endif // _di_controller_data_t_
-
#ifndef _di_controller_rule_action_t_
enum {
controller_rule_action_type_extended = 1,
controller_rule_items_initialize, \
}
- #define f_macro_controller_rule_setting_t_delete_simple(setting) \
+ #define f_macro_controller_rule_t_delete_simple(setting) \
f_string_dynamic_t_delete_simple(setting.id) \
f_string_dynamic_t_delete_simple(setting.name) \
f_string_dynamic_t_delete_simple(setting.pid) \
f_macro_controller_rule_item_t_delete_simple(setting.items)
#endif // _di_controller_rule_t_
+#ifndef _di_controller_rules_t_
+ typedef struct {
+ controller_rule_t *array;
+
+ f_array_length_t size;
+ f_array_length_t used;
+ } controller_rules_t;
+
+ #define controller_rules_initialize \
+ { \
+ 0, \
+ 0, \
+ 0, \
+ }
+
+ #define f_macro_controller_rules_t_delete_simple(rules) \
+ rules.used = rules.size; \
+ while (rules.used > 0) { \
+ rules.used--; \
+ f_macro_controller_rule_t_delete_simple(rules.array[rules.used]); \
+ if (!rules.used) { \
+ if (f_memory_delete((void **) & rules.array, sizeof(controller_rule_t), rules.size)) { \
+ rules.size = 0; \
+ } \
+ } \
+ }
+#endif // _di_controller_rules_t_
+
+#ifndef _di_controller_setting_t
+ typedef struct {
+ bool interruptable;
+
+ f_string_dynamic_t path_setting;
+
+ controller_rules_t rules;
+ } controller_setting_t;
+
+ #define controller_setting_t_initialize \
+ { \
+ F_false, \
+ f_string_dynamic_t_initialize, \
+ controller_rules_t_initialize, \
+ }
+
+ #define f_macro_controller_setting_t_delete_simple(setting) \
+ f_macro_string_dynamic_t_delete_simple(setting.path_setting) \
+ f_macro_string_dynamic_t_delete_simple(setting.rules)
+#endif // _di_controller_setting_t
+
+#ifndef _di_controller_data_t_
+ typedef struct {
+ f_console_parameter_t parameters[controller_total_parameters];
+
+ f_string_lengths_t remaining;
+ bool process_pipe;
+
+ f_file_t output;
+ fll_error_print_t error;
+ fll_error_print_t warning;
+
+ f_color_context_t context;
+ } controller_data_t;
+
+ #define controller_data_t_initialize \
+ { \
+ controller_console_parameter_t_initialize, \
+ f_string_lengths_t_initialize, \
+ F_false, \
+ f_macro_file_t_initialize(f_type_output, f_type_descriptor_output, f_file_flag_write_only), \
+ fll_error_print_t_initialize, \
+ fll_macro_error_print_t_initialize_warning(), \
+ f_color_context_t_initialize, \
+ }
+#endif // _di_controller_data_t_
+
/**
* Print help.
*
int main(const unsigned long argc, const f_string_t *argv) {
const f_console_arguments_t arguments = { argc, argv };
- controller_data_t data = controller_data_initialize;
+ controller_data_t data = controller_data_t_initialize;
if (f_pipe_input_exists()) {
data.process_pipe = F_true;
#endif // _di_controller_rule_items_increase_by_
#ifndef _di_controller_rule_read_
- f_return_status controller_rule_read(const controller_data_t data, controller_rule_cache_t *cache, controller_rule_t *rule) {
+ f_return_status controller_rule_read(const controller_data_t data, const f_string_static_t rule_id, controller_rule_cache_t *cache, controller_rule_t *rule) {
f_status_t status = F_none;
+ rule->id.used = 0;
rule->items.used = 0;
+ rule->status = F_unknown;
- cache->delimits.used = 0;
cache->comments.used = 0;
+ cache->delimits.used = 0;
cache->buffer_items.used = 0;
cache->contents_items.used = 0;
cache->objects_items.used = 0;
- rule->status = F_found_not;
-
- // @todo construct the rule->id from the file path name, strip the ".rule" extension and only accept the relative part of the path (relative to the base settings directory).
- // @todo the base settings directory should be a configurable string, such as with a "-s/--settings" parameter which defaults to a compiled in value (such as /etc/controller/rules/)".
+ status = fl_string_dynamic_append_nulless(rule_id, &rule->id);
- {
+ if (F_status_is_error(status)) {
+ fll_error_print(data.error, F_status_set_fine(status), "fl_string_dynamic_append_nulless", F_true);
+ }
+ else {
f_file_t file = f_file_t_initialize;
- status = f_file_stream_open(cache->name_file.string, 0, &file);
+ const f_string_length_t file_path_length = rule->id.used;
+ char file_path[file_path_length + 1];
+
+ memcpy(file_path, rule->id.string, rule->id.used);
+
+ status = f_file_stream_open(file_path, 0, &file);
if (F_status_is_error(status)) {
- fll_error_file_print(data.error, F_status_set_fine(status), "f_file_stream_open", F_true, cache->name_file.string, "open", fll_error_file_type_file);
+ fll_error_file_print(data.error, F_status_set_fine(status), "f_file_stream_open", F_true, rule->id.string, "open", fll_error_file_type_file);
}
else {
status = f_file_stream_read(file, 1, &cache->buffer_items);
if (F_status_is_error(status)) {
fll_error_file_print(data.error, F_status_set_fine(status), "f_file_stream_read", F_true, cache->name_file.string, "read", fll_error_file_type_file);
}
- else {
- // Setting to F_none from F_unknown distinguishes the two such that F_none suggests a valid rule and F_unknown is just that, unknown.
- rule->status = F_none;
- }
}
f_file_stream_close(F_true, &file);
-
- if (F_status_is_error(status)) return F_false;
}
- if (cache->buffer_items.used) {
+ if (F_status_is_error_not(status) && cache->buffer_items.used) {
f_string_range_t range = f_macro_string_range_t_initialize(cache->buffer_items.used);
status = fll_fss_basic_list_read(cache->buffer_items, &range, &cache->objects_items, &cache->contents_items, &cache->delimits, 0, &cache->comments);
}
if (F_status_is_error(status)) {
+ status = F_status_set_fine(status);
+
controller_rule_error_print(data.error, *cache);
- // designate that the rule is invalid, for any failure.
- rule->status = F_status_set_error(F_invalid);
+ if (status == F_memory_not) {
+ rule->status = F_memory;
+ }
+ else if (status == F_file_open_max || status == F_space_not || status == F_busy) {
+ rule->status = F_resource;
+ }
+ else if (status == F_access_denied || status == F_filesystem_quota_block || status == F_prohibited || status == F_input_output) {
+ rule->status = F_access;
+ }
+ else if (status == F_interrupted) {
+ rule->status = F_interrupted;
+ }
+ else {
+ rule->status = F_invalid;
+ }
+
+ return F_false;
}
- return status;
+ rule->status = F_none;
+ return F_true;
}
#endif // _di_controller_rule_read_
*
* @param data
* The program data.
+ * @param rule_id
+ * The string identifying the rule.
+ * This is constructed from the path parts to the file without the file extension and without the settings directory prefix.
+ * "/etc/controller/setting/rules/boot/my.rule" would have a rule id of "boot/my".
* @param cache
* A structure for containing and caching relevant data.
* @param rule
* The processed rule.
+ * The rule status will be updated by this function.
*
* @return
- * F_none on success.
- *
- * Errors (with error bit) from: controller_rule_items_increase_by().
- * Errors (with error bit) from: controller_rule_item_read().
- * Errors (with error bit) from: f_file_stream_open().
- * Errors (with error bit) from: f_file_stream_read().
- * Errors (with error bit) from: f_fss_count_lines().
- * Errors (with error bit) from: fl_fss_apply_delimit().
- * Errors (with error bit) from: fl_string_dynamic_partial_append().
- * Errors (with error bit) from: fl_string_dynamic_partial_append_nulless().
- * Errors (with error bit) from: fl_string_dynamic_terminate_after().
- * Errors (with error bit) from: fll_fss_basic_list_read().
+ * F_true on success.
+ * F_false on failure.
*
* @see controller_rule_items_increase_by().
* @see controller_rule_item_read().
* @see fll_fss_basic_list_read().
*/
#ifndef _di_controller_rule_read_
- extern f_return_status controller_rule_read(const controller_data_t data, controller_rule_cache_t *cache, controller_rule_t *rule) f_gcc_attribute_visibility_internal;
+ extern f_return_status controller_rule_read(const controller_data_t data, const f_string_static_t rule_id, controller_rule_cache_t *cache, controller_rule_t *rule) f_gcc_attribute_visibility_internal;
#endif // _di_controller_rule_read_
/**
To disallow all rules in all directories, specify this command and provide no directoies.
Each directory is relative to the settings, such that if the controller rule settings are found in "/etc/controller/rules/", then for a directory called "[directory]" would have a resulting path of: "/etc/controller/rules/[directory]/".
+ The "consider" command is a special case of a "rule" command.
+ All available Content are identical.
+ The difference is that this rule is only processed at this spot at this time if and when some "rule" command (or a "consider" command is determined to be executed) designates that this consideration is required (via "require"), wanted (via "want"), or wished (via "wish").
+ If this is determined to be executed, then this is immediately executed in the designated position and applies all properties as appropriate (such as "asynchronous", for example).
+
The "rule" command immediately executes a given rule file.
The first Content represents the directory in which the rule is to be found (do not include leading or trailing slashes in the name).
The second Content represents the basename for the file representing the desired rule.
"controlled": One Content that is a valid Object name, except for the reserved "main".
"failsafe": One Content that is a valid relative rule file name without the ".rule" extension.
"only": Zero or more Content.
+ "consider": One or more Content.
+ The first Content that is the relative directory path (without any leading/trailing slashes).
+ The second Content that is the basename for a rule file.
+ The third and beyond may only be one of\:
+ - asynchronous
+ - require
+ - wait
"rule": One or more Content.
The first Content that is the relative directory path (without any leading/trailing slashes).
The second Content that is the basename for a rule file.