This is effectively a draft of my ideas and is entirely experimental and incomplete.
I am adding it now because of numerous hard-drive failures and data loss of late.
--- /dev/null
+/* FLL - Level 3
+ * Project: Firewall
+ * Version: 0.5.0
+ * Licenses: lgplv2.1
+ * Programmers: Kevin Day
+ */
+#include <level_3/init.h>
+#include "private-init.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// version printed may be used by scripts, so this will only print the version number and a newline, no extra information or colors
+#ifndef _di_init_print_version_
+ f_return_status init_print_version(f_const init_argument argument) {
+ printf("%s\n", init_version);
+
+ return f_none;
+ }
+#endif // _di_init_print_version_
+
+#ifndef _di_init_print_help_
+ f_return_status init_print_help(f_const init_argument argument) {
+ printf("\n");
+ fl_print_color(f_standard_output, argument.context.title, argument.context.reset, " %s", init_name_long);
+
+ printf("\n");
+ fl_print_color(f_standard_output, argument.context.notable, argument.context.reset, " Version %s", init_version);
+
+ printf("\n\n");
+ fl_print_color(f_standard_output, argument.context.important, argument.context.reset, " Available Options: ");
+
+ printf("\n %s", f_console_symbol_short_enable);
+ fl_print_color(f_standard_output, argument.context.standout, argument.context.reset, f_console_standard_short_help);
+
+ printf(", %s", f_console_symbol_long_enable);
+ fl_print_color(f_standard_output, argument.context.standout, argument.context.reset, f_console_standard_long_help);
+ printf(" Print this help message");
+
+ printf("\n %s", f_console_symbol_short_disable);
+ fl_print_color(f_standard_output, argument.context.standout, argument.context.reset, f_console_standard_short_light);
+
+ printf(", %s", f_console_symbol_long_disable);
+ fl_print_color(f_standard_output, argument.context.standout, argument.context.reset, f_console_standard_long_light);
+ printf(" Output using colors that show up better on light backgrounds");
+
+ printf("\n %s", f_console_symbol_short_disable);
+ fl_print_color(f_standard_output, argument.context.standout, argument.context.reset, f_console_standard_short_no_color);
+
+ printf(", %s", f_console_symbol_long_disable);
+ fl_print_color(f_standard_output, argument.context.standout, argument.context.reset, f_console_standard_long_no_color);
+ printf(" Do not output in color");
+
+ printf("\n %s", f_console_symbol_short_disable);
+ fl_print_color(f_standard_output, argument.context.standout, argument.context.reset, f_console_standard_short_version);
+
+ printf(", %s", f_console_symbol_long_disable);
+ fl_print_color(f_standard_output, argument.context.standout, argument.context.reset, f_console_standard_long_version);
+ printf(" Print only the version number");
+
+ printf("\n %s", f_console_symbol_short_disable);
+ fl_print_color(f_standard_output, argument.context.standout, argument.context.reset, f_console_standard_short_debug);
+
+ printf(", %s", f_console_symbol_long_disable);
+ fl_print_color(f_standard_output, argument.context.standout, argument.context.reset, f_console_standard_long_debug);
+ printf(" Enable debugging");
+
+ printf("\n %s", init_parameter_no_prepare_short_name);
+ fl_print_color(f_standard_output, argument.context.standout, argument.context.reset, f_console_standard_short_debug);
+
+ printf(", %s", init_parameter_no_prepare_long_name);
+ fl_print_color(f_standard_output, argument.context.standout, argument.context.reset, f_console_standard_long_debug);
+ printf(" Do not attempt to process kernel command line or perform any boot-time specific preparations.");
+
+ printf("\n %s", init_parameter_runlevel_short_name);
+ fl_print_color(f_standard_output, argument.context.standout, argument.context.reset, f_console_standard_short_debug);
+
+ printf(", %s", init_parameter_runlevel_long_name);
+ fl_print_color(f_standard_output, argument.context.standout, argument.context.reset, f_console_standard_long_debug);
+ printf(" Specify a custom run level, ignoring the kernel command line runlevel argument.");
+
+ printf("\n\n");
+ fl_print_color(f_standard_output, argument.context.important, argument.context.reset, " Usage: ");
+
+ printf("\n ");
+ fl_print_color(f_standard_output, argument.context.standout, argument.context.reset, init_name);
+
+ printf(" ");
+ fl_print_color(f_standard_output, argument.context.notable, argument.context.reset, "[");
+
+ printf(" options ");
+ fl_print_color(f_standard_output, argument.context.notable, argument.context.reset, "]");
+
+ printf("\n\n");
+
+ return f_none;
+ }
+#endif // _di_init_print_help_
+
+#ifndef _di_init_main_
+ f_return_status init_main(f_const f_s_int argc, f_const f_string argv[], init_argument *argument) {
+ f_status status = f_none;
+ f_status status2 = f_none;
+ f_autochar run_level[init_kernel_runlevel_buffer];
+
+ memset(run_level, 0, sizeof(f_autochar) * init_kernel_runlevel_buffer);
+
+ f_u_short do_socket_file = f_true;
+ f_u_short do_socket_port = f_false;
+
+ status = fl_process_parameters(argc, argv, argument->parameters, init_total_parameters, &argument->remaining);
+
+ // load colors when not told to show no colors
+ if (argument->parameters[init_parameter_no_color].result == f_console_result_none) {
+ fl_new_color_context(status2, argument->context);
+
+ if (status2 == f_none) {
+ fll_colors_load_context(&argument->context, argument->parameters[init_parameter_light].result == f_console_result_found);
+ } else {
+ fprintf(f_standard_error, "Critical Error: unable to allocate memory\n");
+ init_delete_argument((*argument));
+ return status2;
+ }
+ }
+
+ if (f_error_is_error(status)) {
+ status = f_error_set_fine(status);
+
+ if (status == f_no_data) {
+ fl_print_color_line(f_standard_error, argument->context.error, argument->context.reset, "ERROR: One of the parameters you passed requires an additional parameter that you did not pass.");
+ // TODO: there is a way to identify which parameter is incorrect
+ // to do this, one must look for any "has_additional" and then see if the "additional" location is set to 0
+ // nothing can be 0 as that represents the program name, unless argv[] is improperly created
+ } else if (f_macro_test_for_allocation_errors(status)) {
+ fl_print_color_line(f_standard_error, argument->context.error, argument->context.reset, "CRITICAL ERROR: unable to allocate memory");
+ } else if (f_error_set_fine(status) == f_invalid_parameter) {
+ fl_print_color_line(f_standard_error, argument->context.error, argument->context.reset, "INTERNAL ERROR: Invalid parameter when calling fl_process_parameters()");
+ } else {
+ fl_print_color_line(f_standard_error, argument->context.error, argument->context.reset, "INTERNAL ERROR: An unhandled error (%u) has occured while calling fl_process_parameters()", f_error_set_error(status));
+ }
+
+ init_delete_argument((*argument));
+ return f_error_set_error(status);
+ }
+
+
+ if (argument->parameters[init_parameter_runlevel].result == f_console_result_found) {
+ const f_u_int parameter_length = strlen(argv[argument->parameters[init_parameter_runlevel].additional.array[0]]);
+
+ // if the run_level value is greater than the static buffer size, ignore the entire string rather than process a cut off value.
+ if (parameter_length > 0 && parameter_length < init_kernel_runlevel_buffer) {
+ strncpy(&run_level, argv[argument->parameters[init_parameter_runlevel].additional.array[0]], parameter_length);
+ }
+ }
+
+
+ // before doing anything make sure that the rootfs has been properly setup.
+ if (argument->parameters[init_parameter_no_prepare].result == f_console_result_none) {
+ init_prepare_system(&run_level);
+ }
+
+ // make sure appropriate required directories exist.
+ init_prepare_init();
+
+
+ // attempt to load the main rule before forking and starting child processes.
+ {
+ // @todo: should this pre-scan the main rule file to see if there is a custom chroot command, if so, change behavior to process rules and then chroot into a new system (cleaning up resources as much as possible before doing chroot) (don't fork child processes?)?
+ // 1) check the last object for a chroot command in reverse order.
+ // - if the chroot fails then additional rules may apply. the chroot command does not have to be the last command.
+ // 2) if chroot is not specified, then continue onto code below.
+ // 3) if chroot is specified, then execute rules directly and exit this process on success (via chroot command).
+ // 4) if chroot is specified, but chroot fails, then continue processing rules and then exit this process (dropping to bash shell).
+ // effectively use my initrd_init and pre_init code here.
+
+ // @todo: init_process_main_rule();
+ }
+
+
+ // commented out code is an alternative method to avoid using malloc for stacks passed to clone.
+ //f_char stack_services[init_stack_size_small_services];
+ //f_char stack_control_file[init_stack_size_small_control_file];
+ init_stack_memory stack_memory = init_stack_memory_initialize;
+
+ status = init_initialize_stack_memory(&stack_memory);
+ if (f_error_is_error(status)) {
+ init_delete_argument((*argument));
+ init_delete_stack_memory(&stack_memory);
+ return status;
+ }
+
+ {
+ f_pid_t pid_services = clone(init_handler_child_services, stack_memory.services + init_stack_size_services, init_flags_clone, stack_memory.services);
+
+ if (pid_services < 0) {
+ fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: Failed to clone services process (errno = %i).", errno);
+ }
+
+ f_pid_t pid_control_file = clone(init_handler_child_control_file, stack_memory.control_file + init_stack_size_control_file, init_flags_clone, stack_memory.control_file);
+
+ if (pid_control_file < 0) {
+ fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: Failed to clone control via file process (errno = %i).", errno);
+ }
+
+
+ // block signals
+ f_sigset_t signal_mask;
+ f_siginfo_t signal_information;
+
+ memset(&signal_mask, 0, sizeof(f_sigset_t));
+ memset(&signal_information_parent, 0, sizeof(f_siginfo_t));
+
+ // block all signals.
+ sigfillset(&signal_mask);
+ sigprocmask(SIG_BLOCK, &signal_mask, 0);
+
+
+ // sit and wait for signals.
+ while (1) {
+ signal_result = sigwaitinfo(&signal_mask, &signal_information);
+
+ if (signal_result < 0) {
+ if (errno == EAGAIN) {
+ // do nothing.
+ continue;
+ }
+ else if (errno != EINTR) {
+ fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: sigwaitinfo() failed (errno = %i).", errno);
+
+ signal_problem_count++;
+ if (signal_problem_count > PROBLEM_COUNT_MAX_SIGNAL_SIZE) {
+ fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: max signal problem count has been reached, sleeping for a period of time.", errno);
+ sleep(init_panic_signal_sleep_seconds);
+ signal_problem_count = 0;
+ }
+
+ continue;
+ }
+ }
+
+ signal_problem_count = 0;
+
+ if (signal_information_parent.si_signo == SIGHUP) {
+ // @todo: close all child process connections? try using small initial memory instead?
+ }
+ else if (signal_information_parent.si_signo == SIGINT {
+ // check the status of processes to see if they are still running, if not, then restart them.
+ }
+ else if (signal_information_parent.si_signo == SIGQUIT || signal_information_parent.si_signo == SIGTERM) {
+ // @todo: block these or attempt to respawn init process? try using small initial memory instead?
+ break;
+ }
+ else if (signal_information_parent.si_signo == SIGSEGV || signal_information_parent.si_signo == SIGBUS || signal_information_parent.si_signo == SIGILL || signal_information_parent.si_signo == SIGFPE) {
+ // @todo: block these or attempt to respawn init process?
+ }
+ else if (signal_information_parent.si_signo == SIGPWR) {
+ // @todo: shutdown process?
+ }
+ else if (signal_information_parent.si_signo == SIGABRT || signal_information_parent.si_signo == SIGIOT || signal_information_parent.si_signo == SIGXCPU) {
+ // do nothing.
+ }
+ else if (signal_information_parent.si_signo == SIGCHLD) {
+ // @todo: restart child processes? try using large initial memory instead?
+ }
+
+ memset(&signal_information, 0, sizeof(siginfo_t));
+ continue;
+ }
+ }
+
+ init_delete_argument((*argument));
+ init_delete_stack_memory(&stack_memory);
+ return status;
+ }
+#endif // _di_init_main_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/* FLL - Level 3
+ * Project: Firewall
+ * Version: 0.1.0
+ * Licenses: lgplv2.1
+ * Programmers: Kevin Day
+ * Documentation:
+ *
+ * This is the Kevux Operating System Init program.
+ * This program utilizes the Featureless Linux Library.
+ *
+ * This init program is designed to run with certain paths and if they do not exist, it will attemp to create them.
+ * This expects the kevux path permissions structure and naming, so a valid /etc/group file should exist.
+ *
+ * This is designed to have different threads handling the following actions:
+ * Thread Group 1 (Signals and Output)
+ * - (parent process) handles/blocks all signals for init program and handles children accordingly.
+ *
+ * Thread Group 2 (Services)
+ * - Handles starting and stopping of individual services.
+ * - New thread created for each user.
+ *
+ * Thread Group 3 (Reporting)
+ * - Handles output to the terminal or any other supported devices.
+ * - No child threads.
+ *
+ * Thread Group 4 (Commands: Time)
+ * - Handles time based processing.
+ * - This is a cron system.
+ * - 2 Child threads:
+ * 1) Cron-style behavior.
+ * 2) Anacron-style behavior.
+ *
+ * Thread Group 5 (Commands: Socket File)
+ * - If socket file is enabled, then this thread is created to listen on the socket file and process received commands.
+ * - No child threads.
+ *
+ * Thread Group 6 (Commands: Socket Port)
+ * - If socket port is enabled, then this thread is created to listen on the socket port and process received commands.
+ * - No child threads.
+ *
+ *
+ * Time based (aka: cron) functionality is being implemented here because cron jobs often need to run as specific users.
+ * The init program is already root and can already switch users, so give it control.
+ * This avoids having yet another program that must have root privileges.
+ *
+ * It would be nice to be able to start the init program as a non-root user who has elevated privileges similar to root.
+ * - That is, have ability to su to any user (except root).
+ * - While this will still be a security concern, not running as root will significantly reduce the potential problems.
+ * - This design would not allow for root-specific cron jobs.
+ */
+#ifndef _init_h
+
+// libc includes
+#include <stdio.h>
+#include <string.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <linux/limits.h> // defines PATH_MAX
+#include <sys/mount.h>
+#include <sys/types.h>
+#include <regex.h>
+#include <malloc.h>
+#include <stdlib.h>
+
+// private includes
+#include "private-init.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _di_init_version_
+ #define init_major_version "0"
+ #define init_minor_version "5"
+ #define init_micro_version "0"
+ #define init_version init_major_version "." init_minor_version "." init_micro_version
+#endif // _di_init_version_
+
+#ifndef _di_init_name_
+ #define init_name "init"
+ #define init_name_long "Kevux Init Program"
+#endif // _di_init_name_
+
+#ifndef _di_init_default_allocation_step_
+ #define init_default_allocation_step f_memory_default_allocation_step
+#endif // _di_init_default_allocation_step_
+
+#ifndef _di_init_paths_
+ // @todo: this will eventually be written to use the f_paths project.
+ #define init_paths_rootfs "/"
+ #define init_paths_devices "/dev/"
+ #define init_paths_devices_pts "/dev/pts/"
+ #define init_paths_system "/sys/"
+ #define init_paths_processes "/proc/"
+ #define init_paths_temporary "/tmp/"
+ #define init_paths_mount "/mnt/"
+ #define init_paths_run "/run/"
+ #define init_paths_init_run "/run/init/"
+ #define init_paths_init_settings "/etc/init/"
+ #define init_paths_init_socket "/run/init/socket/"
+ #define init_paths_init_process "/run/init/process/"
+ #define init_paths_init_log "/log/init/"
+ #define init_paths_log "/log/"
+#endif // _di_init_paths_
+
+#ifndef _di_init_extension_
+ #define init_extension_settings "settings"
+ #define init_extension_rule "rule"
+ #define init_extension_socket "socket"
+ #define init_extension_process "pid"
+#endif // _di_init_extension_
+
+#ifndef _di_init_settings_
+ #define init_rule_core "main"
+ #define init_rule_core_file init_paths_init_settings init_rule_core "." init_extension_rule
+
+ #define init_kernel_command_line init_paths_processes "cmdline"
+ #define init_kernel_runlevel "\\<runlevel=[[:alnum:][:punct:]]*"
+ #define init_kernel_runlevel_ignore 9
+ #define init_kernel_runlevel_buffer 256
+#endif // _di_init_settings_
+
+#ifndef _di_init_socket_
+ #define init_socket_control "control"
+#endif // _di_init_settings_
+
+#ifndef _di_init_groups_
+ #define init_group_devices "d_device"
+ #define init_group_devices_pts "d_devpts"
+ #define init_group_system "k_system"
+ #define init_group_processes "k_process"
+ #define init_group_temporary "d_temporary"
+ #define init_group_mount "d_mount"
+ #define init_group_run "d_run"
+ #define init_group_init_run "d_init_run"
+ #define init_group_init_settings "d_init_settings"
+ #define init_group_init_socket "d_init_socket"
+ #define init_group_init_process "d_init_process"
+ #define init_group_init_log "d_log"
+ #define init_group_process_null "p_null"
+ #define init_group_process_zero "p_zero"
+ #define init_group_process_console "p_terminal"
+ #define init_group_process_random "p_random"
+ #define init_group_process_urandom "p_random"
+#endif // _di_init_groups_
+
+#ifndef _di_init_defines_
+ #define init_parameter_runlevel_short_name "r"
+ #define init_parameter_no_prepare_short_name "n"
+
+ #define init_parameter_runlevel_long_name "run_level"
+ #define init_parameter_no_prepare_long_name "no_prepare"
+
+ enum {
+ init_parameter_help,
+ init_parameter_light,
+ init_parameter_no_color,
+ init_parameter_version,
+ init_parameter_debug,
+ init_parameter_runlevel,
+ init_parameter_no_prepare,
+ };
+
+ #ifdef _en_init_debug_
+ #define f_console_parameter_initialize_init \
+ { \
+ f_console_parameter_initialize(f_console_standard_short_help, f_console_standard_long_help, 0, 0, f_false, f_console_type_normal, 0), \
+ f_console_parameter_initialize(f_console_standard_short_light, f_console_standard_long_light, 0, 0, f_false, f_console_type_inverse, 0), \
+ f_console_parameter_initialize(f_console_standard_short_no_color, f_console_standard_long_no_color, 0, 0, f_false, f_console_type_inverse, 0), \
+ f_console_parameter_initialize(f_console_standard_short_version, f_console_standard_long_version, 0, 0, f_false, f_console_type_inverse, 0), \
+ f_console_parameter_initialize(f_console_standard_short_debug, f_console_standard_long_debug, 0, 0, f_false, f_console_type_inverse, 0), \
+ f_console_parameter_initialize(init_parameter_runlevel_short_name, init_parameter_runlevel_long_name, 0, 0, f_true, f_console_type_normal, 0), \
+ f_console_parameter_initialize(init_parameter_no_prepare_short_name, init_parameter_no_prepare_long_name, 0, 0, f_true, f_console_type_normal, 0), \
+ }
+
+ #define init_total_parameters 7
+ #else
+ #define f_console_parameter_initialize_init \
+ { \
+ f_console_parameter_initialize(f_console_standard_short_help, f_console_standard_long_help, 0, 0, f_false, f_console_type_normal, 0), \
+ f_console_parameter_initialize(f_console_standard_short_light, f_console_standard_long_light, 0, 0, f_false, f_console_type_inverse, 0), \
+ f_console_parameter_initialize(f_console_standard_short_no_color, f_console_standard_long_no_color, 0, 0, f_false, f_console_type_inverse, 0), \
+ f_console_parameter_initialize(f_console_standard_short_version, f_console_standard_long_version, 0, 0, f_false, f_console_type_inverse, 0), \
+ f_console_parameter_initialize(init_parameter_runlevel_short_name, init_parameter_runlevel_long_name, 0, 0, f_true, f_console_type_normal, 0), \
+ f_console_parameter_initialize(init_parameter_no_prepare_short_name, init_parameter_no_prepare_long_name, 0, 0, f_true, f_console_type_normal, 0), \
+ }
+
+ #define init_total_parameters 6
+ #endif // _en_init_debug_
+#endif // _di_init_defines_
+
+#ifndef _di_init_argument_
+ typedef struct {
+ f_console_parameter parameters[init_total_parameters];
+
+ fl_color_context context;
+ } init_argument;
+
+ #define init_argument_initialize \
+ { \
+ f_console_parameter_initialize_init, \
+ fl_color_context_initialize, \
+ }
+
+ #define init_delete_argument(status, argument) \
+ memset(&argument.parameters, 0, sizeof(f_console_parameter) * init_total_parameters); \
+ fl_delete_color_context(status, argument.context);
+
+ #define init_destroy_argument(status, argument) \
+ memset(&argument.parameters, 0, sizeof(f_console_parameter) * init_total_parameters); \
+ fl_destroy_color_context(status, argument.context);
+#endif // _di_init_argument_
+
+#ifndef _di_init_print_version_
+ f_extern f_return_status init_print_version(f_const init_argument data);
+#endif // _di_init_print_version_
+
+#ifndef _di_init_print_help_
+ f_extern f_return_status init_print_help(f_const init_argument data);
+#endif // _di_init_print_help_
+
+#ifndef _di_init_main_
+ f_extern f_return_status init_main(f_const f_s_int argc, f_const f_string argv[], init_argument *data);
+#endif // _di_init_main_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _init_h
--- /dev/null
+#include <level_3/init.h>
+
+int main(f_const f_s_int argc, f_const f_string argv[]) {
+ init_argument data = init_argument_initialize;
+
+ return init_main(argc, argv, &data);
+}
--- /dev/null
+/**
+ * Private source file for firewall.c.
+ */
+#include <level_3/init.h>
+#include "private-init.h"
+
+#ifndef _di_init_rule_buffer_
+ f_return_status init_rule_buffer(f_const f_string filename, f_dynamic_string *buffer, f_fss_objects *objects, f_fss_contents *contents) {
+ f_file file = f_file_initialize;
+ f_status status = f_none;
+ f_file_position file_position = f_file_position_initialize;
+
+ status = f_file_open(&file, filename);
+
+ if (f_error_is_error(status)) {
+ status = f_error_set_fine(status);
+
+ if (optional) {
+ if (status == f_invalid_parameter) {
+ fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: Invalid parameter when calling f_file_open().");
+ } else if (status != f_file_not_found && status != f_file_open_error && status != f_file_descriptor_error) {
+ fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: An unhandled error (%u) has occured while calling f_file_open().", f_error_set_error(status));
+ }
+ } else {
+ if (status == f_invalid_parameter) {
+ fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: Invalid parameter when calling f_file_open().");
+ } else if (status == f_file_not_found) {
+ fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: Unable to find the file '%s'.", filename);
+ } else if (status == f_file_open_error) {
+ fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: Unable to open the file '%s'.", filename);
+ } else if (status == f_file_descriptor_error) {
+ fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: File descriptor error while trying to open the file '%s'.", filename);
+ } else {
+ fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: An unhandled error (%u) has occured while calling f_file_open().", f_error_set_error(status));
+ }
+ }
+
+ return f_error_set_error(status);
+ }
+
+ f_macro_file_reset_position(file_position, file)
+
+ fflush(stdout);
+ status = fl_file_read(file, file_position, buffer);
+
+ f_file_close(&file);
+
+ if (f_error_is_error(status)) {
+ status = f_error_set_fine(status);
+
+ if (status == f_invalid_parameter) {
+ fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: Invalid parameter when calling fl_file_read().");
+ } else if (status == f_overflow) {
+ fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: Integer overflow while trying to buffer the file '%s'.", filename);
+ } else if (status == f_file_not_open) {
+ fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: The file '%s' is no longer open.", filename);
+ } else if (status == f_file_seek_error) {
+ fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: A seek error occurred while accessing the file '%s'.", filename);
+ } else if (status == f_file_read_error) {
+ fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: A read error occurred while accessing the file '%s'.", filename);
+ } else if (f_macro_test_for_allocation_errors(status)) {
+ fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "CRITICAL ERROR: unable to allocate memory.");
+ } else {
+ fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: An unhandled error (%u) has occured while calling fl_file_read().", f_error_set_error(status));
+ }
+
+ return f_error_set_error(status);
+ } else {
+ f_string_location input = f_string_location_initialize;
+
+ input.stop = buffer->used - 1;
+
+ status = fll_fss_basic_list_read(buffer, &input, objects, contents);
+ }
+
+ if (f_error_is_error(status)) {
+ status = f_error_set_fine(status);
+
+ if (status == f_invalid_parameter) {
+ fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: Invalid parameter when calling fll_fss_basic_list_read() for the file '%s'.", filename);
+ } else if (status == f_no_data_on_eos || status == f_no_data || status == f_no_data_on_stop) {
+ fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "ERROR: No relevant data was found within the file '%s'.", filename);
+ } else if (f_macro_test_for_allocation_errors(status)) {
+ fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "CRITICAL ERROR: unable to allocate memory.");
+ } else {
+ fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: An unhandled error (%u) has occured while calling fll_fss_basic_list_read() for the file '%s'.", f_error_set_error(status), filename);
+ }
+
+ return f_error_set_error(status);
+ }
+
+ return status;
+ }
+#endif // _di_init_rule_buffer_
+
+#ifndef _di_init_rules_process_main_
+ f_return_status init_rules_process_main(f_const init_data) {
+ f_status status = f_none;
+ f_status status2 = f_none;
+
+ // @todo: resume replacing code below.
+ status = fll_fss_extended_read(&buffer, input, &local->rule_objects, &local->rule_contents);
+
+ if (f_error_is_not_error(status)) {
+ status = firewall_perform_commands(*local, *data);
+
+ if (f_error_is_error(status)) {
+ status = f_error_set_fine(status);
+
+ if (f_macro_test_for_allocation_errors(status)) {
+ fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "CRITICAL ERROR: unable to allocate memory.");
+ } else if (status == f_failure) {
+ // the error message has already been displayed.
+ } else {
+ fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: An unhandled error (%u) has occured while calling firewall_perform_commands().", f_error_set_error(status));
+ }
+
+ f_delete_fss_objects(status2, local->rule_objects);
+ f_delete_fss_contents(status2, local->rule_contents);
+ return f_error_set_error(status);
+ }
+ }
+
+ f_delete_fss_objects(status2, local->rule_objects);
+ f_delete_fss_contents(status2, local->rule_contents);
+ return status;
+ }
+#endif // _init_rules_process_main_
+
+#ifndef _di_init_handler_child_services_
+ f_return_status init_handler_child_services(f_void_p argument) {
+ init_local_data *local_data = (init_local_data *) argument;
+
+ // load and process rules.
+
+ return f_none;
+ }
+#endif // _di_init_handler_child_services_
+
+#ifndef _di_init_handler_child_control_file_
+ f_return_status init_handler_child_control_file(f_void_p argument) {
+ init_local_data *local_data = (init_local_data *) argument;
+
+ return f_none;
+ }
+#endif // _di_init_handler_child_control_file_
+
+#ifndef _di_init_initialize_stack_memory_
+ f_return_status init_initialize_stack_memory(init_stack_memory *stack_memory) {
+ stack_memory->services = mmap(0, init_stack_size_small_services, init_stack_protections, init_stack_flags, -1, 0);
+ stack_memory->control_file = mmap(0, init_stack_size_small_control_file, init_stack_protections, init_stack_flags, -1, 0);
+
+ if (stack_memory->services == (f_void_p) -1) {
+ return f_failure;
+ }
+
+ if (stack_memory->control_file == (f_void_p) -1) {
+ return f_failure;
+ }
+
+ return f_none;
+ }
+#endif // _di_init_initialize_stack_memory_
+
+#ifndef _di_init_delete_stack_memory_
+ f_return_status init_delete_stack_memory(init_stack_memory *stack_memory) {
+ f_status status = f_none;
+
+ if (stack_memory->services > 0) {
+ if (munmap(stack_memory->services, 0) >= 0) {
+ stack_memory->services = 0;
+ }
+ else {
+ status = f_failure;
+ }
+ }
+
+ if (stack_memory->control_file > 0) {
+ if (munmap(stack_memory->control_file, 0) >= 0) {
+ stack_memory->control_file = 0;
+ }
+ else {
+ status = f_failure;
+ }
+ }
+
+ return status;
+ }
+#endif // _di_init_delete_stack_memory_
+
+#ifndef _di_init_prepare_system_
+ f_return_status init_prepare_system(f_autochar *run_level) {
+ f_status status = f_none;
+ f_stat stat;
+
+ memset(&stat, 0, sizeof(f_stat));
+
+
+ // create the required directories if they do not already exist and then perform appropriate mount.
+ status = f_file_stat(init_paths_devices, &stat);
+
+ if (status == f_file_not_found || status == f_error_set_error(f_invalid_directory)) {
+ system(init_program_mkdir " -p " init_paths_devices);
+ memset(&stat, 0, sizeof(f_stat));
+ }
+
+ system(init_program_mount " " init_paths_devices);
+
+ status = f_file_stat(init_paths_system, &stat);
+
+ if (status == f_file_not_found || status == f_error_set_error(f_invalid_directory)) {
+ system(init_program_mkdir " -p " init_paths_system);
+ memset(&stat, 0, sizeof(f_stat));
+ }
+
+ system(init_program_mount " -p " init_paths_system);
+
+ status = f_file_stat(init_paths_devices_pts, &stat);
+
+ if (status == f_file_not_found || status == f_error_set_error(f_invalid_directory)) {
+ system(init_program_mkdir " -p " init_paths_devices_pts);
+ memset(&stat, 0, sizeof(f_stat));
+ }
+
+ system(init_program_mount " -t " init_paths_devices_pts);
+
+ status = f_file_stat(init_paths_log, &stat);
+
+ if (status == f_file_not_found || status == f_error_set_error(f_invalid_directory)) {
+ system(init_program_mkdir " -p " init_paths_log);
+ memset(&stat, 0, sizeof(f_stat));
+ }
+
+ system(init_program_mount " " init_paths_log);
+
+ status = f_file_stat(var_run_path, &stat);
+
+ if (status == f_file_not_found || status == f_error_set_error(f_invalid_directory)) {
+ system(init_program_mkdir " -p " var_run_path);
+ memset(&stat, 0, sizeof(f_stat));
+ }
+
+ system(init_program_mount " " var_run_path);
+
+ status = f_file_stat(mnt_path, &stat);
+
+ if (status == f_file_not_found || status == f_error_set_error(f_invalid_directory)) {
+ system(init_program_mkdir " -p " mnt_path);
+ memset(&stat, 0, sizeof(f_stat));
+ }
+
+ system(init_program_mount " " mnt_path);
+
+ status = f_file_stat(tmp_path, &stat);
+
+ if (status == f_file_not_found || status == f_error_set_error(f_invalid_directory)) {
+ system(init_program_mkdir " -p " tmp_path);
+ memset(&stat, 0, sizeof(f_stat));
+ }
+
+ system(init_program_mount " " tmp_path);
+
+ status = f_file_stat(init_paths_processes, &stat);
+
+ if (status == f_file_not_found || status == f_error_set_error(f_invalid_directory)) {
+ system(init_program_mkdir " -p " init_paths_processes);
+ memset(&stat, 0, sizeof(f_stat));
+ }
+
+ // Look for the kernel command line to determine whether or not the proc is mounted.
+ // doing this also allows for unusual circumstances where the kernel command line is not mounted but a custom kernel command line is statically provided.
+ status = f_file_stat(init_kernel_command_line, &stat);
+
+ if (status == f_file_not_found) {
+ system(init_program_mount " " init_paths_processes);
+ }
+
+
+ // create the required devices
+ system(init_program_mknod " -m 0660 " init_path_device_null " c 1 3");
+ system(init_program_mknod " -m 0660 " init_path_device_zero " c 1 5");
+ system(init_program_mknod " -m 0660 " init_path_device_console " c 5 1");
+ system(init_program_mknod " -m 0440 " init_path_device_random " c 1 8");
+ system(init_program_mknod " -m 0440 " init_path_device_urandom " c 1 9");
+ system(init_program_chgrp " " init_group_process_null " " init_path_device_null);
+ system(init_program_chgrp " " init_group_process_zero " " init_path_device_zero);
+ system(init_program_chgrp " " init_group_process_console " " init_path_device_console);
+ system(init_program_chgrp " " init_group_process_random " " init_path_device_random);
+ system(init_program_chgrp " " init_group_process_urandom " " init_path_device_urandom);
+
+
+ // attempt to load kernel command line, but do not stop on failure.
+ if (run_level > 0 && run_level[0] != 0) {
+ f_file_p kernel_command_line_file = 0;
+ f_string kernel_command_line_string = f_string_initialize;
+ size_t kernel_command_line_length = 0;
+
+ kernel_command_line_file = fopen(init_kernel_command_line, "ro");
+
+ if (kernel_command_line_file > 0) {
+ getline(&kernel_command_line_string, &kernel_command_line_length, kernel_command_line_file);
+
+ if (kernel_command_line_file) {
+ fclose(kernel_command_line_file);
+ }
+ }
+
+ if (kernel_command_line_length > 0) {
+ regex_t expression;
+ regmatch_t match;
+ f_u_int reg_result = 0;
+ f_u_int string_length = 0;
+
+ reg_result = do_regex_match(&expression, &match, kernel_command_line_string, init_kernel_runlevel);
+
+ if (reg_result == REG_OK) {
+ string_length = match.rm_eo - match.rm_so - init_kernel_runlevel_ignore;
+
+ // if the run_level value is greater than the static buffer size, ignore the entire string rather than process a cut off value.
+ if (string_length > 0 && string_length < init_kernel_runlevel_buffer) {
+ strncpy(run_level, kernel_command_line_string + match.rm_so + init_kernel_runlevel_ignore, string_length);
+ }
+ }
+ }
+
+ if (kernel_command_line_string) {
+ f_status status_free = f_none;
+ f_delete_string(status_free, kernel_command_line_string, string_length);
+ }
+ }
+
+ return f_none;
+ }
+#endif // _di_init_prepare_system_
+
+#ifndef _di_init_prepare_system_
+ f_return_status init_prepare_system() {
+ f_status status = f_none;
+ f_stat stat;
+
+ memset(&stat, 0, sizeof(f_stat));
+
+ // @fixme: this is implemented using user space tools.
+ // such a design allows for quick implementation but I consider this bad practice.
+ // work towards replacing this with custom functions.
+
+ // create the required directories if they do not already exist and then perform appropriate mount.
+ status = f_file_stat(init_paths_devices, &stat);
+ if (status == f_file_not_found || status == f_error_set_error(f_invalid_directory)) {
+ system(init_program_mkdir " -p " init_paths_devices);
+ memset(&stat, 0, sizeof(f_stat));
+ }
+
+ system(init_program_mount " " init_paths_devices);
+
+ status = f_file_stat(init_paths_system, &stat);
+
+ if (status == f_file_not_found || status == f_error_set_error(f_invalid_directory)) {
+ system(init_program_mkdir " -p " init_paths_system);
+ memset(&stat, 0, sizeof(f_stat));
+ }
+
+ system(init_program_mount " -p " init_paths_system);
+
+ status = f_file_stat(init_paths_devices_pts, &stat);
+
+ if (status == f_file_not_found || status == f_error_set_error(f_invalid_directory)) {
+ system(init_program_mkdir " -p " init_paths_devices_pts);
+ memset(&stat, 0, sizeof(f_stat));
+ }
+
+ system(init_program_mount " -t " init_paths_devices_pts);
+
+ status = f_file_stat(init_paths_log, &stat);
+
+ if (status == f_file_not_found || status == f_error_set_error(f_invalid_directory)) {
+ system(init_program_mkdir " -p " init_paths_log);
+ memset(&stat, 0, sizeof(f_stat));
+ }
+
+ system(init_program_mount " " init_paths_log);
+
+ status = f_file_stat(var_run_path, &stat);
+
+ if (status == f_file_not_found || status == f_error_set_error(f_invalid_directory)) {
+ system(init_program_mkdir " -p " var_run_path);
+ memset(&stat, 0, sizeof(f_stat));
+ }
+
+ system(init_program_mount " " var_run_path);
+
+ status = f_file_stat(mnt_path, &stat);
+
+ if (status == f_file_not_found || status == f_error_set_error(f_invalid_directory)) {
+ system(init_program_mkdir " -p " mnt_path);
+ memset(&stat, 0, sizeof(f_stat));
+ }
+
+ system(init_program_mount " " mnt_path);
+
+ status = f_file_stat(tmp_path, &stat);
+
+ if (status == f_file_not_found || status == f_error_set_error(f_invalid_directory)) {
+ system(init_program_mkdir " -p " tmp_path);
+ memset(&stat, 0, sizeof(f_stat));
+ }
+
+ system(init_program_mount " " tmp_path);
+
+
+ // create the required devices
+ system(init_program_mknod " -m 0660 " init_path_device_null " c 1 3");
+ system(init_program_mknod " -m 0660 " init_path_device_zero " c 1 5");
+ system(init_program_mknod " -m 0660 " init_path_device_console " c 5 1");
+ system(init_program_mknod " -m 0440 " init_path_device_random " c 1 8");
+ system(init_program_mknod " -m 0440 " init_path_device_urandom " c 1 9");
+ system(init_program_chgrp " " init_group_process_null " " init_path_device_null);
+ system(init_program_chgrp " " init_group_process_zero " " init_path_device_zero);
+ system(init_program_chgrp " " init_group_process_console " " init_path_device_console);
+ system(init_program_chgrp " " init_group_process_random " " init_path_device_random);
+ system(init_program_chgrp " " init_group_process_urandom " " init_path_device_urandom);
+
+ return f_none;
+ }
+#endif // _di_init_prepare_system_
+
+#ifndef _di_init_prepare_init_
+ f_return_status init_prepare_init() {
+ f_stat stat;
+
+ memset(&stat, 0, sizeof(f_stat));
+
+ // @fixme: this is implemented using user space tools.
+ // such a design allows for quick implementation but I consider this bad practice.
+ // work towards replacing this with custom functions.
+
+ status = f_file_stat(init_paths_init_run, &stat);
+
+ if (status == f_file_not_found || status == f_error_set_error(f_invalid_directory)) {
+ system(init_program_mkdir " -p " init_paths_init_run);
+ system(init_program_chgrp " " init_group_init_run " " init_paths_init_run);
+ memset(&stat, 0, sizeof(f_stat));
+ }
+
+ status = f_file_stat(init_paths_init_settings, &stat);
+
+ if (status == f_file_not_found || status == f_error_set_error(f_invalid_directory)) {
+ system(init_program_mkdir " -p " init_paths_init_settings);
+ system(init_program_chgrp " " init_group_init_settings " " init_paths_init_settings);
+ memset(&stat, 0, sizeof(f_stat));
+ }
+
+ status = f_file_stat(init_paths_init_socket, &stat);
+
+ if (status == f_file_not_found || status == f_error_set_error(f_invalid_directory)) {
+ system(init_program_mkdir " -p " init_paths_init_socket);
+ system(init_program_chgrp " " init_group_init_socket " " init_paths_init_socket);
+ memset(&stat, 0, sizeof(f_stat));
+ }
+
+ status = f_file_stat(init_paths_init_process, &stat);
+
+ if (status == f_file_not_found || status == f_error_set_error(f_invalid_directory)) {
+ system(init_program_mkdir " -p " init_paths_init_process);
+ system(init_program_chgrp " " init_group_init_process " " init_paths_init_process);
+ memset(&stat, 0, sizeof(f_stat));
+ }
+
+ status = f_file_stat(init_paths_init_log, &stat);
+
+ if (status == f_file_not_found || status == f_error_set_error(f_invalid_directory)) {
+ system(init_program_mkdir " -p " init_paths_init_log);
+ system(init_program_chgrp " " init_group_init_log " " init_paths_init_log);
+ memset(&stat, 0, sizeof(f_stat));
+ }
+
+ memset(&stat, 0, sizeof(f_stat));
+
+ return f_none;
+ }
+#endif // _di_init_prepare_init_
+
+#ifndef _di_init_process_main_rule_
+ f_return_status init_process_main_rule(const init_argument argument, f_dynamic_string *buffer, init_data *data) {
+ f_status status = f_none;
+ f_dynamic_string buffer = f_dynamic_string_initialize;
+ f_string_location location = f_string_location_initialize;
+ f_fss_objects objects = f_fss_objects_initialize;
+ f_fss_contents contents = f_fss_contents_initialize;
+ f_string_length position = f_string_length_initialize;
+
+ // load the main file into memory.
+ status = init_rule_buffer(init_rule_core_file, &buffer, &objects, &contents);
+
+ if (f_error_is_error(status)) {
+ status = f_error_set_fine(status);
+
+ if (status == f_invalid_parameter) {
+ fl_print_color_line(f_standard_error, argument.context.error, argument.context.reset, "INTERNAL ERROR: Invalid parameter when calling fll_fss_basic_list_read() for the file '%s'.", init_rule_core_file);
+ } else if (status == f_no_data_on_eos || status == f_no_data || status == f_no_data_on_stop) {
+ fl_print_color_line(f_standard_error, argument.context.error, argument.context.reset, "ERROR: No relevant data was found within the file '%s'.", init_rule_core_file);
+ } else if (f_macro_test_for_allocation_errors(status)) {
+ fl_print_color_line(f_standard_error, argument.context.error, argument.context.reset, "CRITICAL ERROR: unable to allocate memory.");
+ } else {
+ fl_print_color_line(f_standard_error, argument.context.error, argument.context.reset, "INTERNAL ERROR: An unhandled error (%u) has occured while calling fll_fss_basic_list_read() for the file '%s'.", f_error_set_error(status), init_rule_core_file);
+ }
+
+ f_delete_dynamic_string(buffer);
+ f_delete_fss_objects(objects);
+ f_delete_fss_contents(contents);
+ return status;
+ }
+
+ while (position < objects.used) {
+ location.start = objects.array[position].start;
+ location.stop = objects.array[position].stop;
+
+ status = fll_fss_extended_read(&buffer, &location, &objects, &contents);
+
+ position++;
+ } // while
+
+ // @fixme: resume here, below is just notes and copy&pasted code as examples/reminders.
+
+ /*
+ status = fll_fss_extended_read(&buffer, &location, &objects, &contents);
+
+ if (f_error_is_error(status_process)) {
+ if (f_macro_test_for_allocation_errors(status)) {
+ fl_print_color_line(f_standard_error, argument->context.error, argument->context.reset, "CRITICAL ERROR: unable to allocate memory.");
+ }
+ else {
+ fl_print_color_line(f_standard_error, argument->context.error, argument->context.reset, "INTERNAL ERROR: An unhandled error (%u) has occured while calling init_load_main_rule().", f_error_set_error(status));
+ }
+
+ init_delete_argument((*argument));
+ init_delete_stack_memory(&stack_memory);
+ return status_process;
+ }
+ */
+
+
+ /*
+ f_status status = f_none;
+ f_status status2 = f_none;
+
+ status = fll_fss_extended_read(buffer, location, objects, contents);
+
+ if (f_error_is_not_error(status)) {
+ // @todo: process objects and contents.
+ // execute individual processes.
+
+ if (f_error_is_error(status)) {
+ status = f_error_set_fine(status);
+
+ if (f_macro_test_for_allocation_errors(status)) {
+ fl_print_color_line(f_standard_error, data->context.error, context.reset, "CRITICAL ERROR: unable to allocate memory.");
+ } else if (status == f_failure) {
+ // the error message has already been displayed.
+ } else {
+ fl_print_color_line(f_standard_error, data->context.error, data->context.reset, "INTERNAL ERROR: An unhandled error (%u) has occured while calling firewall_perform_commands().", f_error_set_error(status));
+ }
+
+ f_delete_fss_objects(status2, (*rule_objects));
+ f_delete_fss_contents(status2, (*rule_contents));
+ return f_error_set_error(status);
+ }
+ }
+ else {
+ if (f_macro_test_for_allocation_errors(status)) {
+ fl_print_color_line(f_standard_error, context.error, context.reset, "CRITICAL ERROR: unable to allocate memory.");
+ }
+ else {
+ fl_print_color_line(f_standard_error, context.error, context.reset, "INTERNAL ERROR: An unhandled error (%u) has occured while calling init_load_main_rule().", f_error_set_error(status));
+ }
+ }
+
+ f_delete_fss_objects(status2, (*rule_objects));
+ f_delete_fss_contents(status2, (*rule_contents));
+ */
+
+ f_delete_dynamic_string(buffer);
+ f_delete_fss_objects(objects);
+ f_delete_fss_contents(contents);
+ return status;
+ }
+#endif // _di_init_process_main_rule_
--- /dev/null
+/**
+ * Private include file for init.c.
+ */
+
+#ifndef _PRIVATE_init_h
+#define _PRIVATE_init_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// define a custom stack size for each handler.
+// consider mmap():
+// - http://www.evanjones.ca/software/threading.html
+// - http://stackoverflow.com/questions/1083172/how-to-mmap-the-stack-for-the-clone-system-call-on-linux
+// - f_void_p stack = mmap(0,initial_stacksize,PROT_WRITE|PROT_READ,MAP_PRIVATE|MAP_GROWSDOWN|MAP_ANONYMOUS,-1,0);
+// - http://lwn.net/Articles/294001/
+// - http://tiku.io/questions/659065/how-to-mmap-the-stack-for-the-clone-system-call-on-linux
+#define init_stack_size_small_services 6144
+#define init_stack_size_small_control_file 4096
+#define init_stack_size_large_services 12288
+#define init_stack_size_large_control_file 8192
+
+#define init_stack_protections PROT_WRITE | PROT_READ
+#define init_stack_flags MAP_PRIVATE | MAP_GROWSDOWN | MAP_ANONYMOUS
+
+#define init_clone_flags CLONE_FILES | CLONE_FS | CLONE_IO | CLONE_VM | CLONE_SIGHAND | CLONE_THREAD
+
+#define init_panic_signal_sleep_seconds 9
+
+#ifndef _di_init_rule_
+ // rule [directory] [filename (no-extension)] [require] [last] [asynchronous] = execute a rule located in [directory][filename].rule.
+ typedef struct {
+ f_dynamic_string name;
+ f_dynamic_string directory;
+ f_dynamic_string file;
+ f_bool require;
+ f_bool asynchronous;
+ } init_rule;
+
+ #define init_rule_initialize \
+ { \
+ f_dynamic_string_initialize,
+ f_dynamic_string_initialize,
+ f_dynamic_string_initialize,
+ f_bool_initialize,
+ f_bool_initialize,
+ }
+
+ #define delete_init_rule(status, rule) \
+ f_delete_dynamic_string(status, rule.name); \
+ if (status == f_none) { \
+ f_delete_dynamic_string(status, rule.directory); \
+ } \
+ if (status == f_none) { \
+ f_delete_dynamic_string(status, rule.file); \
+ } \
+ if (status == f_none) { \
+ rule.require = 0; \
+ rule.asynchronous = 0; \
+ }
+
+ #define destroy_init_rule(status, rule) \
+ f_destroy_dynamic_string(status, rule.name); \
+ if (status == f_none) { \
+ f_destroy_dynamic_string(status, rule.directory); \
+ } \
+ if (status == f_none) { \
+ f_destroy_dynamic_string(status, rule.file); \
+ } \
+ if (status == f_none) { \
+ rule.require = 0; \
+ rule.asynchronous = 0; \
+ }
+#endif // _di_init_data_
+
+// an array of dynamic strings
+#ifndef _di_init_rules_
+ typedef struct {
+ init_rule *array; // the array of init_rule
+ f_string_length size; // total amount of allocated space
+ f_string_length used; // total number of allocated spaces used
+ } init_rules;
+
+ #define init_rules_initialize { 0, 0, 0 }
+
+ #define f_delete_init_rules(status, rules) \
+ status = f_none; \
+ while (rules.size > 0) { \
+ --rules.size; \
+ delete_init_rule(status, rules.array[rules.size]); \
+ if (status != f_none) break; \
+ } \
+ if (status == f_none) status = f_delete((f_void_p *) & rules.array, sizeof(init_rule), rules.size); \
+ if (status == f_none) rules.used = 0;
+
+ #define f_destroy_init_rules(status, rules) \
+ status = f_none; \
+ while (rules.size > 0) { \
+ --rules.size; \
+ destroy_init_rule(status, rules.array[rules.size]); \
+ if (status != f_none) break; \
+ } \
+ if (status == f_none) status = f_destroy((f_void_p *) & rules.array, sizeof(init_rule), rules.size); \
+ if (status == f_none) rules.used = 0;
+
+ #define f_resize_init_rules(status, rules, new_length) \
+ status = f_none; \
+ if (new_length < rules.size) { \
+ f_string_length i = rules.size - new_length; \
+ for (; i < rules.size; ++i) { \
+ delete_init_rule(status, rules.array[i]); \
+ if (status != f_none) break; \
+ } \
+ } \
+ if (status == f_none) status = f_resize((f_void_p *) & rules.array, sizeof(init_rule), rules.size, new_length); \
+ if (status == f_none) { \
+ if (new_length > rules.size) { \
+ f_string_length i = rules.size; \
+ for (; i < new_length; ++i) { \
+ memset(&rules.array[i], 0, sizeof(f_string)); \
+ } \
+ } \
+ rules.size = new_length; \
+ if (rules.used > rules.size) rules.used = new_length; \
+ }
+
+ #define f_adjust_init_rules(status, rules, new_length) \
+ status = f_none; \
+ if (new_length < rules.size) { \
+ f_string_length i = rules.size - new_length; \
+ for (; i < rules.size; ++i) { \
+ destroy_init_rule(status, rules.array[i]); \
+ if (status != f_none) break; \
+ } \
+ } \
+ if (status == f_none) status = f_adjust((f_void_p *) & rules.array, sizeof(init_rule), rules.size, new_length); \
+ if (status == f_none) { \
+ if (new_length > rules.size) { \
+ f_string_length i = rules.size; \
+ for (; i < new_length; ++i) { \
+ memset(&rules.array[i], 0, sizeof(init_rule)); \
+ } \
+ } \
+ rules.size = new_length; \
+ if (rules.used > rules.size) rules.used = new_length; \
+ }
+#endif // _di_init_rules_
+
+#ifndef _di_init_category_
+ // category [name] = execute rules in the specified list called [name].
+ typedef struct {
+ f_dynamic_string name;
+ init_rule last;
+ } init_category;
+
+ #define init_rule_initialize \
+ { \
+ f_dynamic_string_initialize,
+ init_rule_initialize,
+ }
+
+ #define delete_init_category(status, category) \
+ f_delete_dynamic_string(status, category.name); \
+ if (status == f_none) { \
+ delete_init_rule(status, category.last); \
+ }
+
+ #define destroy_init_category(status, category) \
+ f_destroy_dynamic_string(status, category.name); \
+ if (status == f_none) { \
+ destroy_init_rule(status, category.last); \
+ }
+#endif // _di_init_category_
+
+// an array of dynamic strings
+#ifndef _di_init_categorys_
+ typedef struct {
+ init_category *array; // the array of init_category
+
+ f_string_length size; // total amount of allocated space
+ f_string_length used; // total number of allocated spaces used
+ } init_categorys;
+
+ #define init_categorys_initialize { 0, 0, 0 }
+
+ #define f_delete_init_categorys(status, categorys) \
+ status = f_none; \
+ while (categorys.size > 0) { \
+ --categorys.size; \
+ delete_init_category(status, categorys.array[categorys.size]); \
+ if (status != f_none) break; \
+ } \
+ if (status == f_none) status = f_delete((f_void_p *) & categorys.array, sizeof(init_category), categorys.size); \
+ if (status == f_none) categorys.used = 0;
+
+ #define f_destroy_init_categorys(status, categorys) \
+ status = f_none; \
+ while (categorys.size > 0) { \
+ --categorys.size; \
+ destroy_init_category(status, categorys.array[categorys.size]); \
+ if (status != f_none) break; \
+ } \
+ if (status == f_none) status = f_destroy((f_void_p *) & categorys.array, sizeof(init_category), categorys.size); \
+ if (status == f_none) categorys.used = 0;
+
+ #define f_resize_init_categorys(status, categorys, new_length) \
+ status = f_none; \
+ if (new_length < categorys.size) { \
+ f_string_length i = categorys.size - new_length; \
+ for (; i < categorys.size; ++i) { \
+ delete_init_category(status, categorys.array[i]); \
+ if (status != f_none) break; \
+ } \
+ } \
+ if (status == f_none) status = f_resize((f_void_p *) & categorys.array, sizeof(init_category), categorys.size, new_length); \
+ if (status == f_none) { \
+ if (new_length > categorys.size) { \
+ f_string_length i = categorys.size; \
+ for (; i < new_length; ++i) { \
+ memset(&categorys.array[i], 0, sizeof(f_string)); \
+ } \
+ } \
+ categorys.size = new_length; \
+ if (categorys.used > categorys.size) categorys.used = new_length; \
+ }
+
+ #define f_adjust_init_categorys(status, categorys, new_length) \
+ status = f_none; \
+ if (new_length < categorys.size) { \
+ f_string_length i = categorys.size - new_length; \
+ for (; i < categorys.size; ++i) { \
+ destroy_init_category(status, categorys.array[i]); \
+ if (status != f_none) break; \
+ } \
+ } \
+ if (status == f_none) status = f_adjust((f_void_p *) & categorys.array, sizeof(init_category), categorys.size, new_length); \
+ if (status == f_none) { \
+ if (new_length > categorys.size) { \
+ f_string_length i = categorys.size; \
+ for (; i < new_length; ++i) { \
+ memset(&categorys.array[i], 0, sizeof(init_category)); \
+ } \
+ } \
+ categorys.size = new_length; \
+ if (categorys.used > categorys.size) categorys.used = new_length; \
+ }
+#endif // _di_init_categorys_
+
+#ifndef _di_init_data_
+ typedef struct {
+ f_string socket_file;
+ f_u_int socket_port;
+ f_u_int socket_id_target;
+ f_u_int socket_id_client;
+
+ f_u_short timeout_start;
+ f_u_short timeout_stop;
+ f_u_short timeout_kill;
+
+ init_rules main_rules;
+ init_categorys main_categorys;
+ init_rule main_failsafe;
+ } init_data;
+
+ #define init_data_initialize \
+ { \
+ f_string_initialize, \
+ 0, \
+ 0, \
+ 0, \
+ 2, \
+ 2, \
+ 1, \
+ init_rules_initialize, \
+ init_categorys_initialize, \
+ init_rule_initialize, \
+ }
+#endif // _di_init_data_
+
+typedef struct {
+ f_void_p services;
+ f_void_p reporting;
+ f_void_p time;
+ f_void_p control_file;
+ f_void_p control_port;
+ f_void_p login_file;
+ f_void_p login_port;
+
+ init_argument argument;
+ init_data data;
+} init_stack_memory;
+
+#define init_stack_memory_initialize \
+ { \
+ 0, \
+ 0, \
+ 0, \
+ 0, \
+ 0, \
+ 0, \
+ 0, \
+ init_argument_initialize, \
+ init_data_initialize, \
+ }
+
+// custom settings to prepare the init process.
+// this is not self-contained and depends on user space applications to exist.
+#define init_program_umount "umount"
+#define init_program_mount "mount"
+#define init_program_mkdir "mkdir"
+#define init_program_chmod "chmod"
+#define init_program_chgrp "chgrp"
+#define init_program_mknod "mknod"
+#define init_program_ln "ln"
+
+#define init_path_device_console init_paths_devices "console"
+#define init_path_device_zero init_paths_devices "zero"
+#define init_path_device_null init_paths_devices "null"
+#define init_path_device_random init_paths_devices "random"
+#define init_path_device_urandom init_paths_devices "urandom"
+
+#define init_path_processes_cmdline init_paths_processes "cmdline"
+#define init_path_processes_mounts init_paths_processes "mounts"
+
+#ifndef _di_init_rule_buffer_
+ f_return_status init_rule_buffer(f_const f_string filename, f_dynamic_string *buffer, f_fss_objects *objects, f_fss_contents *contents) f_gcc_attribute_visibility_internal;
+#endif // _di_init_rule_buffer_
+
+#ifndef _di_init_handler_child_services_
+ // start, stop, and handle signals to services.
+ f_return_status init_handler_child_services(f_void_p argument) f_gcc_attribute_visibility_internal;
+#endif // _di_init_handler_child_services_
+
+#ifndef _di_init_handler_child_control_file_
+ // listens on a socket file and accepts control commands.
+ f_return_status init_handler_child_control_file(f_void_p argument) f_gcc_attribute_visibility_internal;
+#endif // _di_init_handler_child_socket_file_
+
+#ifndef _di_init_initialize_stack_memory_
+ f_return_status init_initialize_stack_memory(init_stack_memory *stack_memory) f_gcc_attribute_visibility_internal;
+#endif // _di_init_initialize_stack_memory_
+
+#ifndef _di_init_delete_stack_memory_
+ f_return_status init_delete_stack_memory(init_stack_memory *stack_memory) f_gcc_attribute_visibility_internal;
+#endif // _di_init_delete_stack_memory_
+
+#ifndef _di_init_prepare_system_
+ f_return_status init_prepare_system() f_gcc_attribute_visibility_internal;
+#endif // _di_init_prepare_system_
+
+#ifndef _di_init_prepare_init_
+ f_return_status init_prepare_init() f_gcc_attribute_visibility_internal;
+#endif // _di_init_prepare_init_
+
+#ifndef _di_init_process_main_rule_
+ f_return_status init_process_main_rule(const init_argument argument, f_dynamic_string *buffer, init_data *data) f_gcc_attribute_visibility_internal;
+#endif // _di_init_process_main_rule_
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // _PRIVATE_init_h
--- /dev/null
+f_types
+f_errors
+f_strings
+f_memory
+f_pipe
+f_print
+f_console
+f_fss
+fl_console
+fl_file
+fl_strings
+fl_colors
+fl_directory
+fl_fss
+fll_colors
+fll_fss
+fll_execute
--- /dev/null
+# fss-0002
+# category [name] = execute rules in the specified list called [name].
+# failsafe [name] = a list whose rules get executed when required rules fail.
+# rule [directory] [filename (no-extension)] [require] [last] [asynchronous] = execute a rule located in [directory][filename].rule.
+# If [require] is specified, then execute failsafe list.
+# If [last] is specified, then execution ceases with this list or rule.
+# If [asynchronous] is specified, then execution of this rule will be run asynchronously.
+# timeout [start|stop|kill] [seconds] provide a default time setting in seconds.
+#
+# this file is only used for booting.
+
+main:
+ timeout start 7
+ timeout stop 7
+ timeout kill 3
+
+ category boot
+ category net
+ category time
+ category console
+
+ failsafe maintenance last
+
+maintenance:
+ timeout start 2
+ timeout stop 2
+ timeout kill 1
+
+ rule maintenance console
+
+boot:
+ rule boot filesystem require
+ rule boot modules require
+ rule boot devices require
+ rule target logger
+ rule target dbus
+
+net:
+ rule net all
+
+time:
+ rule service clock
+
+console:
+ rule program terminal require
+ rule target mouse
--- /dev/null
+# fss-0002
+
+main:
+ name boot-devices
+
+script:
+ start {
+ ip addr add 127.0.0.1/8 label lo dev lo;
+ ip link set lo up;
+ }
+
+ stop {
+ ip link set lo down;
+ }
--- /dev/null
+# fss-0002
+# the first list to be executed, will be called 'main' and is broken up into the following fss-0000 or fss-0001 content.
+# name = an identifier that this rule represents. The first rule with this identifier name to be successfully executed will cease all other uses of this list.
+# need = all of the rule identifiers that represent rules required to be executed (and succeed) before this starts.
+# want = all of the rule identifiers that represent rules required to be executed (but not succeed) before this starts.
+# wish = all of the rule identifiers that represents rules that would be prefered to be executed before this starts.
+# variable [variable name] [filename] [file format] [count number] = a variable to be loaded and used by lists in this rule.
+# [variable name] = name of the variable in both the file and in the rule
+# [filename] = name of the file stored in.
+# [file format] = the format to read the file and load the variable. Supported formats: raw, fss-0000, fss-0001, fss-0002, fss-0003.
+# [count number] = select a specific occurance of the [variable name] within the [filename].
+#
+# each list, following the 'main' list will have a name that represents how it gets executed.
+# 'command' represents a list with the single-line fss-0000 rules 'start', 'stop', 'restart', and 'reload' that get directly passed.
+# not providing restart means that a 'start' and then 'stop' is used.
+# not providing reload makes reload do nothing.
+# providing 'start', 'stop', 'restart', or 'reload' but having no values means that the command will not be provided.
+#
+# 'script' represents a list broken up into multiple fss-0003 lists: 'start', 'stop', 'restart', and 'reload'.
+# not providing restart means thata 'start' and then 'stop' is used.
+# not providing reload makes reload do nothing.
+# providing 'start', 'stop', 'restart', or 'reload' but having no values means that the command will not be provided.
+#
+# 'target' represents a 'command' list that expects a given pid file to be created by the program or created by this program.
+# example pid line: 'pid program /run/program/name.pid' or: 'pid init /run/program/name.pid', such that 'program' tells the init program to expect the target to create the pid file and 'init' to expect this program to create the pid file.
+# not providing stop will result in the init program reading the pid file and terminating the process by the pid.
+# not providing restart means that a 'start' and then 'stop' is used.
+# not providing reload makes reload do nothing.
+# not providing start will result in no action on start.
+# providing a 'stop' that is blank will result in no action on stop.
+#
+# 'timeout' [start|stop|kill] represents an amount of time to wait for pid file before considering the start, stop, or kill as problematic.
+# providing a blank start or stop will result in an indefinite wait.
+# kill will be called after stop fails and process is still running.
+# providing a blank kill will result in kill not being executed when stop fails.
+#
+# each list, except for main, will be executed in a top down order (synchronously).
+#
+# each script, command, and target will support the following settings:
+# 'user' the user id to switch to before executing/processing.
+# 'group' the group id to switch to before executing/processing.
+
+main:
+ name boot-filesystem
+
+command:
+ start mount -a -O no_netdev
+ stop umount -arf -O no_netdev
+
+command:
+ start swapon -a
+ stop swapoff -a
--- /dev/null
+# fss-0002
+
+default:
+ name boot-modules
+ need boot-filesystem
+
+script:
+ start {
+ if [[ ! -f /proc/modules ]] ; then
+ exit 0;
+ fi
+
+ if [[ ! -e /lib/modules/$(uname -r)/modules.dep ]] ; then
+ depmod;
+ fi
+
+ return 0;
+ }
+
+ stop {
+ video_line=$(dmesg | grep -s -o '^\[drm] [[:alpha:]]* defaulting to [[:alpha:]]* modesetting.$')
+
+ if [[ $(echo $video_line | grep -s -o '\<kernel modesetting\>') != "" ]] ; then
+ modesetting=kernel
+ else
+ modesetting=user
+ fi
+
+ video_card=$(echo $video_line | grep -s -o '^\[drm] [[:alpha:]]* defaulting' | sed -e 's|^\[drm] ||' -e 's| defaulting$||')
+
+ # handle nouveau
+ if [[ $video_card == "" ]] ; then
+ video_line=$(dmesg | grep -s -o '^\[drm] Initialized nouveau .*$')
+
+ if [[ $video_line != "" ]] ; then
+ video_line=$(dmesg | grep -s -o '^fbcon: nouveaufb (fb0) is primary device$')
+
+ if [[ $video_line != "" ]] ; then
+ modesetting=kernel
+ video_card=nouveau
+ fi
+ fi
+ fi
+
+ if [[ $modesetting == "user" ]] ; then
+ video_line=$(dmesg | grep -s -o '^fbcon: NV.* (fb0) is primary device$')
+
+ if [[ $video_line != "" ]] ; then
+ video_card=nv
+ fi
+
+ if [[ $video_card == "" ]] ; then
+ video_line=$(dmesg | grep -s -o '^fbcon: radeon.*fb (fb0) is primary device$')
+
+ if [[ $video_line != "" ]] ; then
+ video_card=radeon
+ fi
+ fi
+
+ if [[ $video_card == "" ]] ; then
+ video_line=$(dmesg | grep -s -o '^fbcon: .* Radeon .* (fb0) is primary device$')
+
+ if [[ $video_line != "" ]] ; then
+ video_card=radeon
+ fi
+ fi
+
+ if [[ $video_card == "" ]] ; then
+ video_line=$(dmesg | grep -s -o '^fbcon: intel.*fb (fb0) is primary device$')
+
+ if [[ $video_line != "" ]] ; then
+ video_card=intel
+ fi
+ fi
+ fi
+
+ if [[ ! -f /dev/modesetting ]] ; then
+ echo $modesetting > /dev/modesetting
+ chmod u+rw-x,g+r-wx,o-rwx /dev/modesetting
+ chgrp e_xorg /dev/modesetting
+ fi
+
+ if [[ ! -f /dev/video_card ]] ; then
+ echo $video_card > /dev/video_card
+ chmod u+rw-x,g+r-wx,o-rwx /dev/video_card
+ chgrp e_xorg /dev/video_card
+ fi
+ }
--- /dev/null
+# fss-0002
+
+main:
+ name net-all
+
+command:
+ start network start
+ stop network stop
+ restart network restart
--- /dev/null
+# fss-0002
+
+main:
+ name net-loopback
+
+script:
+ start {
+ ip addr add 127.0.0.1/8 label lo dev lo;
+ ip link set lo up;
+ }
+
+ stop {
+ ip link set lo down;
+ }
--- /dev/null
+# fss-0002
+
+main:
+ name program-terminal
+ want boot-modules
+
+target:
+ start qingy tty1 -d -l -n -t
+ pid init /run/tty/tty1.pid
+
+target:
+ start qingy tty2 -d -l -n -t
+ pid init /run/tty/tty2.pid
+
+target:
+ start qingy tty3 -d -l -n -t
+ pid init /run/tty/tty3.pid
+
+target:
+ start qingy tty4 -d -l -n -t
+ pid init /run/tty/tty4.pid
--- /dev/null
+# fss-0002
+
+main:
+ name
+
+script:
+ start {
+ clock_mode=$(fss_basic_read -c 0 -n mode /etc/clock);
+
+ if [[ $clock_mode == "local" ]] ; then
+ hwclock --hctosys;
+ elif [[ $clock_mode == "ntpdate" ]] ; then
+ ntpdate $(fss_basic_read -c 0 -n server /etc/clock) &&
+ hwclock --systohc --utc
+ elif [[ $clock_mode == "ntp" ]] ; then
+ if [[ $(fss_basic_read -c 0 -n ntpdate /etc/clock) == "yes" ]] ; then
+ ntpdate $(fss_basic_read -c 0 -n server /etc/clock) &&
+ hwclock --systohc --utc
+ fi
+ elif [[ $clock_mode == "utc" ]] ; then
+ hwclock --hctosys --utc;
+ fi
+ }
--- /dev/null
+# fss-0002
+
+main:
+ name target-dbus
+
+target:
+ start dbus-daemon --system --fork
+ pid target /run/dbus/dbus.pid
--- /dev/null
+# fss-0002
+
+main:
+ name target/logger
+
+target:
+ start metalog -B -p /run/logger/logger.pid -C /etc/logger.conf
+ pid target /run/logger/logger.pid
+
--- /dev/null
+# fss-0002
+
+main:
+ name target-mouse
+ want boot/modules
+ variable device /etc/mouse fss-0000
+ variable protocol /etc/mouse fss-0000
+ variable options /etc/mouse fss-0000
+
+target:
+ start gpm -m [device] -t [protocol] [options]
+ pid /run/mouse/mouse.pid