]> Kevux Git Server - fll/commitdiff
Progress: add the current (draft) of the custom init program
authorKevin Day <thekevinday@gmail.com>
Sun, 17 Jan 2016 20:29:41 +0000 (14:29 -0600)
committerKevin Day <thekevinday@gmail.com>
Sun, 17 Jan 2016 20:29:41 +0000 (14:29 -0600)
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.

17 files changed:
level_3/init/c/init.c [new file with mode: 0644]
level_3/init/c/init.h [new file with mode: 0644]
level_3/init/c/main.c [new file with mode: 0644]
level_3/init/c/private-init.c [new file with mode: 0644]
level_3/init/c/private-init.h [new file with mode: 0644]
level_3/init/data/build/dependencies [new file with mode: 0644]
level_3/init/data/settings/core.rule [new file with mode: 0644]
level_3/init/data/settings/rules/boot/devices.rule [new file with mode: 0644]
level_3/init/data/settings/rules/boot/filesystem.rule [new file with mode: 0644]
level_3/init/data/settings/rules/boot/modules.rule [new file with mode: 0644]
level_3/init/data/settings/rules/net/all.rule [new file with mode: 0644]
level_3/init/data/settings/rules/net/loopback.rule [new file with mode: 0644]
level_3/init/data/settings/rules/program/terminal.rule [new file with mode: 0644]
level_3/init/data/settings/rules/service/clock.rule [new file with mode: 0644]
level_3/init/data/settings/rules/target/dbus.rule [new file with mode: 0644]
level_3/init/data/settings/rules/target/logger.rule [new file with mode: 0644]
level_3/init/data/settings/rules/target/mouse.rule [new file with mode: 0644]

diff --git a/level_3/init/c/init.c b/level_3/init/c/init.c
new file mode 100644 (file)
index 0000000..81496e9
--- /dev/null
@@ -0,0 +1,280 @@
+/* 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
diff --git a/level_3/init/c/init.h b/level_3/init/c/init.h
new file mode 100644 (file)
index 0000000..ecbcb65
--- /dev/null
@@ -0,0 +1,230 @@
+/* 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
diff --git a/level_3/init/c/main.c b/level_3/init/c/main.c
new file mode 100644 (file)
index 0000000..0d78d61
--- /dev/null
@@ -0,0 +1,7 @@
+#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);
+}
diff --git a/level_3/init/c/private-init.c b/level_3/init/c/private-init.c
new file mode 100644 (file)
index 0000000..648275d
--- /dev/null
@@ -0,0 +1,587 @@
+/**
+ * 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_
diff --git a/level_3/init/c/private-init.h b/level_3/init/c/private-init.h
new file mode 100644 (file)
index 0000000..745c8cf
--- /dev/null
@@ -0,0 +1,364 @@
+/**
+ * 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
diff --git a/level_3/init/data/build/dependencies b/level_3/init/data/build/dependencies
new file mode 100644 (file)
index 0000000..3d9fca4
--- /dev/null
@@ -0,0 +1,17 @@
+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
diff --git a/level_3/init/data/settings/core.rule b/level_3/init/data/settings/core.rule
new file mode 100644 (file)
index 0000000..51207d7
--- /dev/null
@@ -0,0 +1,46 @@
+# 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
diff --git a/level_3/init/data/settings/rules/boot/devices.rule b/level_3/init/data/settings/rules/boot/devices.rule
new file mode 100644 (file)
index 0000000..b62bdb2
--- /dev/null
@@ -0,0 +1,14 @@
+# 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;
+  }
diff --git a/level_3/init/data/settings/rules/boot/filesystem.rule b/level_3/init/data/settings/rules/boot/filesystem.rule
new file mode 100644 (file)
index 0000000..ec18c8b
--- /dev/null
@@ -0,0 +1,52 @@
+# 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
diff --git a/level_3/init/data/settings/rules/boot/modules.rule b/level_3/init/data/settings/rules/boot/modules.rule
new file mode 100644 (file)
index 0000000..468635d
--- /dev/null
@@ -0,0 +1,88 @@
+# 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
+  }
diff --git a/level_3/init/data/settings/rules/net/all.rule b/level_3/init/data/settings/rules/net/all.rule
new file mode 100644 (file)
index 0000000..b09acbc
--- /dev/null
@@ -0,0 +1,9 @@
+# fss-0002
+
+main:
+  name net-all
+
+command:
+  start network start
+  stop network stop
+  restart network restart
diff --git a/level_3/init/data/settings/rules/net/loopback.rule b/level_3/init/data/settings/rules/net/loopback.rule
new file mode 100644 (file)
index 0000000..aa6b169
--- /dev/null
@@ -0,0 +1,14 @@
+# 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;
+  }
diff --git a/level_3/init/data/settings/rules/program/terminal.rule b/level_3/init/data/settings/rules/program/terminal.rule
new file mode 100644 (file)
index 0000000..766fde1
--- /dev/null
@@ -0,0 +1,21 @@
+# 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
diff --git a/level_3/init/data/settings/rules/service/clock.rule b/level_3/init/data/settings/rules/service/clock.rule
new file mode 100644 (file)
index 0000000..1edf634
--- /dev/null
@@ -0,0 +1,23 @@
+# 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
+  }
diff --git a/level_3/init/data/settings/rules/target/dbus.rule b/level_3/init/data/settings/rules/target/dbus.rule
new file mode 100644 (file)
index 0000000..369ab3f
--- /dev/null
@@ -0,0 +1,8 @@
+# fss-0002
+
+main:
+  name target-dbus
+
+target:
+  start dbus-daemon --system --fork
+  pid target /run/dbus/dbus.pid
diff --git a/level_3/init/data/settings/rules/target/logger.rule b/level_3/init/data/settings/rules/target/logger.rule
new file mode 100644 (file)
index 0000000..eaa1d51
--- /dev/null
@@ -0,0 +1,9 @@
+# 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
+
diff --git a/level_3/init/data/settings/rules/target/mouse.rule b/level_3/init/data/settings/rules/target/mouse.rule
new file mode 100644 (file)
index 0000000..40aa768
--- /dev/null
@@ -0,0 +1,12 @@
+# 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