From: Kevin Day Date: Sun, 23 Nov 2025 04:59:39 +0000 (-0600) Subject: Update: Initial import, using firewall 0.7.3. X-Git-Tag: 0.7.3^0 X-Git-Url: https://www.git.kevux.org/?a=commitdiff_plain;h=e67c98cdc9d032b3cd7bb61e5ad936284ffe06d2;p=kevux-firewall Update: Initial import, using firewall 0.7.3. This pulls in the built project extracted from the FLL 0.7.3 release. --- e67c98cdc9d032b3cd7bb61e5ad936284ffe06d2 diff --git a/bootstrap.sh b/bootstrap.sh new file mode 100755 index 0000000..7185d63 --- /dev/null +++ b/bootstrap.sh @@ -0,0 +1,3039 @@ +#!/bin/bash +# license: lgpl-2.1-or-later +# programmer: Kevin Day +# +# The purpose of this script is to provide a simple bootstrap tool to compile any part of the FLL project. +# +# The dependencies of this script are: bash, basename, cp, dirname, grep, ln, mkdir, rm, sed, and touch. +# +# This script is only designed specifically for bootstrap compiling the FLL project and does not necessarily fully follow the fake (featureless make) build process. +# +# This script can also be run under zsh rather than bash by setting the environment variable SHELL_ENGINE to "zsh", such as: +# SHELL_ENGINE="zsh" zsh ./bootstrap.sh --help +# + +bootstrap_main() { + local IFS=$' \t\n' # Prevent IFS exploits by overriding with a local scope. + + if [[ ${SHELL_ENGINE} == "zsh" ]] ; then + emulate ksh + fi + + local public_name="Simple FLL Bootstrap Script" + local system_name=bootstrap + local called_name=$(basename ${0}) + local version=0.7.3 + + local grab_next= + local do_color=dark + local do_help= + local do_copyright= + local i=0 + local m= + local p= + local t=0 + + local c_reset="\\033[0m" + local c_title="\\033[1;33m" + local c_error="\\033[1;31m" + local c_warning="\\033[0;33m" + local c_highlight="\\033[1;32m" + local c_notice="\\033[0;01m" + local c_important="\\033[0;32m" + local c_subtle="\\033[1;30m" + local c_prefix="\\" + + local key= + local -A variables=() + local define_extra= + local failure=0 + local settings_name=settings + local settings_file= + local settings_defines= + local mode= + local modes= + local modes_available= + local operation= + local operation_failure= + local path_build=build/ + local path_build_stage=build/stage/ + local path_data=data/ + local path_documentation=${path_data}documentation/ + local path_settings=${path_data}settings/ + local path_sources=sources/ + local path_language=c/ + local path_work= + local process= + local project_built= + local project_built_shared= + local project_built_static= + local project_label= + local override_path_build= + local override_path_data= + local override_path_sources= + local override_path_work= + local stage= + local verbosity=normal + local verbose= + local verbose_common= + + local enable_documentation= + local enable_shared= + local enable_static= + + if [[ ${#} -gt 0 ]] ; then + t=${#} + + while [[ ${i} -lt ${t} ]] ; do + let i=${i}+1 + + if [[ ${SHELL_ENGINE} == "zsh" ]] ; then + p=${(P)i} + else + p=${!i} + fi + + if [[ ${grab_next} == "" ]] ; then + if [[ ${p} == "-h" || ${p} == "--help" ]] ; then + do_help=yes + elif [[ ${p} == "+C" || ${p} == "++copyright" ]] ; then + do_copyright="yes" + elif [[ ${p} == "+d" || ${p} == "++dark" ]] ; then + do_color=dark + context="+d" + elif [[ ${p} == "+l" || ${p} == "++light" ]] ; then + do_color=light + context="+l" + elif [[ ${p} == "+n" || ${p} == "++no_color" ]] ; then + do_color=none + context="+n" + elif [[ ${p} == "+Q" || ${p} == "++quiet" ]] ; then + verbosity="quiet" + verbose="+Q" + verbose_common= + elif [[ ${p} == "+E" || ${p} == "++error" ]] ; then + verbosity="error" + verbose="+E" + verbose_common= + elif [[ ${p} == "+N" || ${p} == "++normal" ]] ; then + verbosity= + verbose="+N" + verbose_common= + elif [[ ${p} == "+V" || ${p} == "++verbose" ]] ; then + verbosity="verbose" + verbose="+V" + verbose_common="-v" + elif [[ ${p} == "+D" || ${p} == "++debug" ]] ; then + verbosity="debug" + verbose="+D" + verbose_common="-v" + elif [[ ${p} == "+v" || ${p} == "++version" ]] ; then + echo ${version} + return 0 + elif [[ ${p} == "-d" || ${p} == "--define" ]] ; then + grab_next=define_extra + elif [[ ${p} == "-m" || ${p} == "--mode" ]] ; then + grab_next="mode" + elif [[ ${p} == "-p" || ${p} == "--process" ]] ; then + grab_next="process" + elif [[ ${p} == "-s" || ${p} == "--settings" ]] ; then + grab_next=settings_name + elif [[ ${p} == "-b" || ${p} == "--build" ]] ; then + grab_next=path_build + elif [[ ${p} == "-d" || ${p} == "--data" ]] ; then + grab_next=path_data + elif [[ ${p} == "-S" || ${p} == "--sources" ]] ; then + grab_next=path_sources + elif [[ ${p} == "-w" || ${p} == "--work" ]] ; then + grab_next=path_work + elif [[ ${p} == "--enable-doc" ]] ; then + enable_documentation="yes" + elif [[ ${p} == "--disable-doc" ]] ; then + enable_documentation="no" + elif [[ ${p} == "--enable-shared" ]] ; then + enable_shared="yes" + elif [[ ${p} == "--disable-shared" ]] ; then + enable_shared="no" + elif [[ ${p} == "--enable-static" ]] ; then + enable_static="yes" + elif [[ ${p} == "--disable-static" ]] ; then + enable_static="no" + elif [[ ${operation} == "" ]] ; then + operation="${p}" + elif [[ ${operation_failure} == "" ]] ; then + operation_failure=fail-multiple + fi + else + if [[ ${grab_next} == "define_extra" ]] ; then + define_extra="${define_extra}${p} " + elif [[ ${grab_next} == "mode" ]] ; then + modes="${modes}${p} " + elif [[ ${grab_next} == "process" ]] ; then + process="${p}" + elif [[ ${grab_next} == "settings_name" ]] ; then + settings_name="${p}" + elif [[ ${grab_next} == "path_build" ]] ; then + path_build=$(sed -e 's|//*|/|g' -e 's|/*$|/|' <<< ${p}) + override_path_build="y" + elif [[ ${grab_next} == "path_data" ]] ; then + path_data=$(sed -e 's|//*|/|g' -e 's|/*$|/|' <<< ${p}) + override_path_data="y" + elif [[ ${grab_next} == "path_sources" ]] ; then + path_sources=$(sed -e 's|//*|/|g' -e 's|/*$|/|' <<< ${p}) + override_path_sources="y" + elif [[ ${grab_next} == "path_work" ]] ; then + path_work=$(sed -e 's|//*|/|g' -e 's|/*$|/|' <<< ${p}) + override_path_work="y" + fi + + grab_next= + fi + done + + p= + fi + + # If the settings_name has a directory separator, then assume it is a path to the settings file. + if [[ $(grep -sho '/' <<< ${settings_name}) == "" ]] ; then + settings_file="${path_data}build/${settings_name}" + else + settings_file="${settings_name}" + + # Extract the settings name from the path. + settings_name=$(basename ${settings_name}) + fi + + settings_defines="${path_data}build/defines" + path_documentation="${path_data}documentation/" + path_settings="${path_data}settings/" + path_build_stage="${path_build}stage/" + + bootstrap_handle_colors + + if [[ ${do_help} == "yes" ]] ; then + bootstrap_help + bootstrap_cleanup + + return 0 + fi + + if [[ ${do_copyright} == "yes" ]] ; then + bootstrap_copyright + bootstrap_cleanup + + return 0 + fi + + bootstrap_load_settings + + # FSS and Featurless Make supports more flexible mode names, but for the purpose of this bootstrap script and avoiding potential problems, keep it simple. + if [[ ${modes} != "" ]] ; then + for mode in ${modes} ; do + if [[ $(grep -sho '[^_[:alnum:]+-]' <<< ${mode}) != "" ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: The mode ${c_notice}${mode}${c_error} includes invalid characters, only alphanumeric, underscore, minus, and plus are allowed.${c_reset}" + fi + + bootstrap_cleanup + + return 1 + fi + done + fi + + if [[ ${?} -ne 0 ]] ; then + bootstrap_cleanup + + return 1 + fi + + bootstrap_load_settings_mode + + if [[ ${?} -ne 0 ]] ; then + bootstrap_cleanup + + return 1 + fi + + bootstrap_id "build_name" + project_built="${path_build_stage}${variables[${key}]}" + if [[ ${process} != "" ]] ; then + project_built="${project_built}-${process}" + fi + + key= + stage= + bootstrap_id "stage" + if [[ ${variables[${key}]} != "" ]] ; then + stage="-${variables[${key}]}" + fi + + project_built="${project_built}${stage}" + project_built_shared="${project_built}${stage}.shared" + project_built_static="${project_built}${stage}.static" + + if [[ ${modes_available} == "" ]] ; then + if [[ ${modes} != "" ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: The mode(s) ${c_notice}${modes}${c_error} are not a valid modes, there are no available modes.${c_error}${c_reset}" + fi + + bootstrap_cleanup + + return 1 + fi + else + let i=0 + for m in ${modes_available} ; do + + for mode in ${modes} ; do + + if [[ "${mode}" == "${m}" ]] ; then + let i=1 + + break + fi + done + + if [[ ${i} -eq 1 ]] ; then break ; fi + done + + if [[ ${i} -eq 0 ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: The mode(s) ${c_notice}${modes}${c_error} are not valid modes, they must be one of: ${c_notice}${modes_available}${c_error}.${c_reset}" + fi + + bootstrap_cleanup + + return 1 + fi + fi + + bootstrap_id "build_name" + if [[ ${variables[${key}]} == "" ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: The required setting '${c_notice}build_name${c_error}' is not specified in the build settings file '${c_notice}${settings_file}${c_error}'.${c_reset}" + fi + + bootstrap_cleanup + + return 1 + fi + + bootstrap_id "version_major" + if [[ ${variables[${key}]} == "" ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: The required setting '${c_notice}version_major${c_error}' is not specified in the build settings file '${c_notice}${settings_file}${c_error}'.${c_reset}" + fi + + bootstrap_cleanup + + return 1 + fi + + bootstrap_id "version_minor" + if [[ ${variables[${key}]} == "" ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: The required setting '${c_notice}version_minor${c_error}' is not specified in the build settings file '${c_notice}${settings_file}${c_error}'.${c_reset}" + fi + + bootstrap_cleanup + + return 1 + fi + + bootstrap_id "version_micro" + if [[ ${variables[${key}]} == "" ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: The required setting '${c_notice}version_micro${c_error}' is not specified in the build settings file '${c_notice}${settings_file}${c_error}'.${c_reset}" + fi + + bootstrap_cleanup + + return 1 + fi + + if [[ ${path_data} == "" || ! -d ${path_data} ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: The data directory ${c_notice}${path_data}${c_error} is not a valid directory.${c_reset}" + fi + + bootstrap_cleanup + + return 1 + fi + + if [[ ${path_sources} == "" || ! -d ${path_sources} ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: The sources directory ${c_notice}${path_sources}${c_error} is not a valid directory.${c_reset}" + fi + + bootstrap_cleanup + + return 1 + fi + + if [[ ${path_work} != "" && ! -d ${path_work} ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: The work directory ${c_notice}${path_work}${c_error} is not a valid directory.${c_reset}" + fi + + bootstrap_cleanup + + return 1 + fi + + bootstrap_id "build_name" + project_label="${variables[${key}]}" + + bootstrap_id "version_major" + if [[ "${variables[${key}]}" != "" ]] ; then + project_label="${project_label}-${variables[${key}]}" + + bootstrap_id "version_minor" + if [[ "${variables[${key}]}" != "" ]] ; then + project_label="${project_label}.${variables[${key}]}" + + bootstrap_id "version_micro" + if [[ "${variables[${key}]}" != "" ]] ; then + project_label="${project_label}.${variables[${key}]}" + fi + fi + fi + + if [[ ${operation_failure} == "fail-multiple" ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: Only one operation may be specified at a time.${c_reset}" + fi + + bootstrap_cleanup + + return 1 + elif [[ ${operation} == "build" ]] ; then + if [[ ${verbosity} != "quiet" && ${verbosity} != "error" ]] ; then + echo -e "${c_highlight}Building:${c_reset} ${c_notice}${project_label}${c_highlight} with modes: ${c_notice}${modes}${c_highlight}.${c_reset}" + fi + + if [[ ! -f ${project_built}-${settings_name}.prepared ]] ; then + bootstrap_prepare_build + + if [[ ${?} -ne 0 ]] ; then + bootstrap_cleanup + + return 1 + fi + fi + + bootstrap_operation_build + + if [[ ${?} -ne 0 ]] ; then + bootstrap_cleanup + + return 1 + fi + elif [[ ${operation} == "clean" ]] ; then + if [[ ${verbosity} != "quiet" && ${verbosity} != "error" ]] ; then + echo -e "${c_highlight}Cleaning Project:${c_reset} ${c_notice}${project_label}${c_highlight}.${c_reset}" + fi + + bootstrap_operation_clean + elif [[ ${operation} == "" ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: No operation was given.${c_reset}" + fi + + bootstrap_cleanup + + return 1 + else + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: The operation ${c_notice}${operation}${c_error} was not recognized.${c_reset}" + fi + + bootstrap_cleanup + + return 1 + fi + + bootstrap_cleanup + + return 0 +} + +bootstrap_handle_colors() { + + if [[ ${do_color} == "light" ]] ; then + c_error="\\033[1;31m" + c_warning="\\033[0;31m" + c_title="\\033[1;34m" + c_highlight="\\033[0;34m" + c_notice="\\033[0;01m" + c_important="\\033[0;35m" + elif [[ ${do_color} == "none" ]] ; then + c_reset= + c_title= + c_error= + c_warning= + c_highlight= + c_notice= + c_important= + c_subtle= + c_prefix= + fi +} + +bootstrap_help() { + + echo -e "${c_title}${public_name}${c_reset}" + echo -e " ${c_notice}Version ${version}${c_reset}" + echo + echo -e "${c_highlight}${system_name}${c_reset} ${c_notice}[${c_reset} options ${c_notice}]${c_reset} ${c_notice}[${c_reset} operation ${c_notice}]${c_reset}" + echo -e " ${c_important}build${c_reset} Build or compile the code based on build settings file." + echo -e " ${c_important}clean${c_reset} Delete all build files." + echo + echo -e "${c_highlight}Options:${c_reset}" + echo -e " -${c_important}h${c_reset}, --${c_important}help${c_reset} Print this help message." + echo -e " +${c_important}C${c_reset}, ++${c_important}copyright${c_reset} Print the copyright." + echo -e " +${c_important}d${c_reset}, ++${c_important}dark${c_reset} Output using colors that show up better on dark backgrounds." + echo -e " +${c_important}l${c_reset}, ++${c_important}light${c_reset} Output using colors that show up better on light backgrounds." + echo -e " +${c_important}n${c_reset}, ++${c_important}no_color${c_reset} Do not print using color." + echo -e " +${c_important}Q${c_reset}, ++${c_important}quiet${c_reset} Decrease verbosity, silencing most print.to." + echo -e " +${c_important}E${c_reset}, ++${c_important}error${c_reset} Decrease verbosity, using only error print.to." + echo -e " +${c_important}N${c_reset}, ++${c_important}normal${c_reset} Set verbosity to normal." + echo -e " +${c_important}V${c_reset}, ++${c_important}verbose${c_reset} Increase verbosity beyond normal print.to." + echo -e " +${c_important}D${c_reset}, ++${c_important}debug${c_reset} Enable debugging, significantly increasing verbosity beyond normal print.to." + echo -e " +${c_important}v${c_reset}, ++${c_important}version${c_reset} Print only the version number." + echo + echo -e "${c_highlight}Bootstrap Options:${c_reset}" + echo -e " -${c_important}d${c_reset}, --${c_important}define${c_reset} Append an additional define after defines from settings file." + echo -e " -${c_important}m${c_reset}, --${c_important}mode${c_reset} Use this mode when processing the build settings." + echo -e " -${c_important}p${c_reset}, --${c_important}process${c_reset} Process name for storing build states." + echo -e " -${c_important}s${c_reset}, --${c_important}settings${c_reset} Use this settings file, from within the source settings directory." + echo + echo -e " -${c_important}b${c_reset}, --${c_important}build${c_reset} Specify a custom build directory." + echo -e " -${c_important}D${c_reset}, --${c_important}data${c_reset} Specify a custom path to the data files." + echo -e " -${c_important}S${c_reset}, --${c_important}sources${c_reset} Specify a custom path to the source files." + echo -e " -${c_important}w${c_reset}, --${c_important}work${c_reset} Use includes/libraries/programs from this directory instead of system." + echo + echo -e "${c_highlight}Special Options:${c_reset}" + echo -e " --${c_important}enable-doc${c_reset} Forcibly do build documentation files." + echo -e " --${c_important}disable-doc${c_reset} Forcibly do not build documentation files." + echo -e " --${c_important}enable-shared${c_reset} Forcibly do build shared files." + echo -e " --${c_important}disable-shared${c_reset} Forcibly do not build shared files." + echo -e " --${c_important}enable-static${c_reset} Forcibly do build static files." + echo -e " --${c_important}disable-static${c_reset} Forcibly do not build static files." +} + +bootstrap_copyright() { + + echo "Copyright © 2007-2025 Kevin Day." + echo + echo "Source code license lgpl-2.1-or-later." + echo "Standard and specification license open-standard-license-1.0-or-later." + echo "Documentation license cc-by-sa-4.0." +} + +bootstrap_id() { + + case ${1} in + "build_compiler") let key=0;; + "build_indexer") let key=1;; + "build_indexer_arguments") let key=2;; + "build_language") let key=3;; + "build_libraries") let key=4;; + "build_libraries_shared") let key=5;; + "build_libraries_static") let key=6;; + "build_name") let key=7;; + "build_objects_library") let key=8;; + "build_objects_library_shared") let key=9;; + "build_objects_library_static") let key=10;; + "build_objects_program") let key=11;; + "build_objects_program_shared") let key=12;; + "build_objects_program_static") let key=13;; + "build_script") let key=14;; + "build_shared") let key=15;; + "build_sources_documentation") let key=16;; + "build_sources_headers") let key=17;; + "build_sources_headers_shared") let key=18;; + "build_sources_headers_static") let key=19;; + "build_sources_library") let key=20;; + "build_sources_library_shared") let key=21;; + "build_sources_library_static") let key=22;; + "build_sources_object") let key=23;; + "build_sources_object_shared") let key=24;; + "build_sources_object_static") let key=25;; + "build_sources_program") let key=26;; + "build_sources_program_shared") let key=27;; + "build_sources_program_static") let key=28;; + "build_sources_script") let key=29;; + "build_sources_setting") let key=30;; + "build_static") let key=31;; + "defines") let key=32;; + "defines_library") let key=33;; + "defines_library_shared") let key=34;; + "defines_library_static") let key=35;; + "defines_object") let key=36;; + "defines_object_shared") let key=37;; + "defines_object_static") let key=38;; + "defines_program") let key=39;; + "defines_program_shared") let key=40;; + "defines_program_static") let key=41;; + "defines_shared") let key=42;; + "defines_static") let key=43;; + "environment") let key=44;; + "flags") let key=45;; + "flags_library") let key=46;; + "flags_library_shared") let key=47;; + "flags_library_static") let key=48;; + "flags_object") let key=49;; + "flags_object_shared") let key=50;; + "flags_object_static") let key=51;; + "flags_program") let key=52;; + "flags_program_shared") let key=53;; + "flags_program_static") let key=54;; + "flags_shared") let key=55;; + "flags_static") let key=56;; + "has_path_standard") let key=57;; + "modes") let key=58;; + "modes_default") let key=59;; + "path_headers") let key=60;; + "path_language") let key=61;; + "path_library_script") let key=62;; + "path_library_shared") let key=63;; + "path_library_static") let key=64;; + "path_object_script") let key=65;; + "path_object_shared") let key=66;; + "path_object_static") let key=67;; + "path_program_script") let key=68;; + "path_program_shared") let key=69;; + "path_program_static") let key=70;; + "path_sources") let key=71;; + "path_sources_headers") let key=72;; + "path_sources_library") let key=73;; + "path_sources_object") let key=74;; + "path_sources_program") let key=75;; + "path_sources_script") let key=76;; + "preserve_path_headers") let key=77;; + "process_post") let key=78;; + "process_pre") let key=79;; + "search_exclusive") let key=80;; + "search_shared") let key=81;; + "search_static") let key=82;; + "stage") let key=83;; + "version_file") let key=84;; + "version_major") let key=85;; + "version_major_prefix") let key=86;; + "version_micro") let key=87;; + "version_micro_prefix") let key=88;; + "version_minor") let key=89;; + "version_minor_prefix") let key=90;; + "version_nano") let key=91;; + "version_nano_prefix") let key=92;; + "version_target") let key=93;; + + "build_compiler-mode") let key=94;; + "build_indexer-mode") let key=95;; + "build_indexer_arguments-mode") let key=96;; + "build_language-mode") let key=97;; + "build_libraries-mode") let key=98;; + "build_libraries_shared-mode") let key=99;; + "build_libraries_static-mode") let key=100;; + "build_name-mode") let key=101;; + "build_objects_library-mode") let key=102;; + "build_objects_library_shared-mode") let key=103;; + "build_objects_library_static-mode") let key=104;; + "build_objects_program-mode") let key=105;; + "build_objects_program_shared-mode") let key=106;; + "build_objects_program_static-mode") let key=107;; + "build_script-mode") let key=108;; + "build_shared-mode") let key=109;; + "build_sources_documentation-mode") let key=110;; + "build_sources_headers-mode") let key=111;; + "build_sources_headers_shared-mode") let key=112;; + "build_sources_headers_static-mode") let key=113;; + "build_sources_library-mode") let key=114;; + "build_sources_library_shared-mode") let key=115;; + "build_sources_library_static-mode") let key=116;; + "build_sources_object-mode") let key=117;; + "build_sources_object_shared-mode") let key=118;; + "build_sources_object_static-mode") let key=119;; + "build_sources_program-mode") let key=120;; + "build_sources_program_shared-mode") let key=121;; + "build_sources_program_static-mode") let key=122;; + "build_sources_script-mode") let key=123;; + "build_sources_setting-mode") let key=124;; + "build_static-mode") let key=125;; + "defines-mode") let key=126;; + "defines_library-mode") let key=127;; + "defines_library_shared-mode") let key=128;; + "defines_library_static-mode") let key=129;; + "defines_object-mode") let key=130;; + "defines_object_shared-mode") let key=131;; + "defines_object_static-mode") let key=132;; + "defines_program-mode") let key=133;; + "defines_program_shared-mode") let key=134;; + "defines_program_static-mode") let key=135;; + "defines_shared-mode") let key=136;; + "defines_static-mode") let key=137;; + "environment-mode") let key=138;; + "flags-mode") let key=139;; + "flags_library-mode") let key=140;; + "flags_library_shared-mode") let key=141;; + "flags_library_static-mode") let key=142;; + "flags_object-mode") let key=143;; + "flags_object_shared-mode") let key=144;; + "flags_object_static-mode") let key=145;; + "flags_program-mode") let key=146;; + "flags_program_shared-mode") let key=147;; + "flags_program_static-mode") let key=148;; + "flags_shared-mode") let key=149;; + "flags_static-mode") let key=150;; + "has_path_standard-mode") let key=151;; + "path_headers-mode") let key=152;; + "path_language-mode") let key=153;; + "path_library_script-mode") let key=154;; + "path_library_shared-mode") let key=155;; + "path_library_static-mode") let key=156;; + "path_object_script-mode") let key=157;; + "path_object_shared-mode") let key=158;; + "path_object_static-mode") let key=159;; + "path_program_script-mode") let key=160;; + "path_program_shared-mode") let key=161;; + "path_program_static-mode") let key=162;; + "path_sources-mode") let key=163;; + "path_sources_headers-mode") let key=164;; + "path_sources_library-mode") let key=165;; + "path_sources_object-mode") let key=166;; + "path_sources_program-mode") let key=167;; + "path_sources_script-mode") let key=168;; + "preserve_path_headers-mode") let key=169;; + "process_post-mode") let key=170;; + "process_pre-mode") let key=171;; + "search_exclusive-mode") let key=172;; + "search_shared-mode") let key=173;; + "search_static-mode") let key=174;; + "stage-mode") let key=175;; + "version_file-mode") let key=176;; + "version_major-mode") let key=177;; + "version_major_prefix-mode") let key=178;; + "version_micro-mode") let key=179;; + "version_micro_prefix-mode") let key=180;; + "version_minor-mode") let key=181;; + "version_minor_prefix-mode") let key=182;; + "version_nano-mode") let key=183;; + "version_nano_prefix-mode") let key=184;; + "version_target-mode") let key=185;; + + "has-build_compiler") let key=186;; + "has-build_indexer") let key=187;; + "has-build_indexer_arguments") let key=188;; + "has-build_name") let key=189;; + "has-has_path_standard") let key=190;; + "has-path_library_script") let key=191;; + "has-path_library_shared") let key=192;; + "has-path_library_static") let key=193;; + "has-path_object_script") let key=194;; + "has-path_object_shared") let key=195;; + "has-path_object_static") let key=196;; + "has-path_program_script") let key=197;; + "has-path_program_shared") let key=198;; + "has-path_program_static") let key=199;; + "has-path_sources") let key=200;; + "has-path_sources_headers") let key=201;; + "has-path_sources_library") let key=202;; + "has-path_sources_object") let key=203;; + "has-path_sources_program") let key=204;; + "has-path_sources_script") let key=205;; + "has-search_exclusive") let key=206;; + "has-search_shared") let key=207;; + "has-search_static") let key=208;; + "has-stage") let key=209;; + "has-version_major_prefix") let key=210;; + "has-version_micro_prefix") let key=211;; + "has-version_minor_prefix") let key=212;; + "has-version_nano_prefix") let key=213;; + + "has-build_compiler-mode") let key=214;; + "has-build_indexer-mode") let key=215;; + "has-build_indexer_arguments-mode") let key=216;; + "has-build_name-mode") let key=217;; + "has-has_path_standard-mode") let key=218;; + "has-path_library_script-mode") let key=219;; + "has-path_library_shared-mode") let key=220;; + "has-path_library_static-mode") let key=221;; + "has-path_object_script-mode") let key=222;; + "has-path_object_shared-mode") let key=223;; + "has-path_object_static-mode") let key=224;; + "has-path_program_script-mode") let key=225;; + "has-path_program_shared-mode") let key=226;; + "has-path_program_static-mode") let key=227;; + "has-path_sources-mode") let key=228;; + "has-path_sources_headers-mode") let key=229;; + "has-path_sources_library-mode") let key=230;; + "has-path_sources_object-mode") let key=231;; + "has-path_sources_program-mode") let key=232;; + "has-path_sources_script-mode") let key=233;; + "has-search_exclusive-mode") let key=234;; + "has-search_shared-mode") let key=235;; + "has-search_static-mode") let key=236;; + "has-stage-mode") let key=237;; + "has-version_major_prefix-mode") let key=238;; + "has-version_micro_prefix-mode") let key=239;; + "has-version_minor_prefix-mode") let key=240;; + "has-version_nano_prefix-mode") let key=241;; + esac +} + +bootstrap_load_settings() { + local i= + local key= + local value= + + if [[ ! -d ${path_data}build/ ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: No build settings directory '${c_notice}${path_data}build/${c_error}' could not be found or is not a valid directory.${c_reset}" + fi + + let failure=1 + elif [[ ! -f ${settings_file} ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: No settings file ${c_notice}${settings_file}${c_error} could not be found or is not a valid file.${c_reset}" + fi + + let failure=1 + fi + + if [[ ${failure} -eq 1 ]] ; then + return 1 + fi + + # Get available modes. + if [[ ${modes_available} == "" ]] ; then + modes_available=$(grep -sho "^[[:space:]]*modes[[:space:]].*\$" ${settings_file} | sed -e "s|^[[:space:]]*modes\>||" -e 's|^[[:space:]]*||') + fi + + # Get default modes. + modes_default=$(grep -sho "^[[:space:]]*modes_default[[:space:]].*\$" ${settings_file} | sed -e "s|^[[:space:]]*modes_default\>||" -e 's|^[[:space:]]*||') + + # Use default modes if no mode is explicitly provided. + if [[ ${modes} == "" ]] ; then + modes=${modes_default} + fi + + # Single value Objects. + for i in build_compiler build_indexer build_language build_name build_script build_shared build_sources_object build_sources_object_shared build_sources_object_static build_static has_path_standard path_headers path_language path_library_script path_library_shared path_library_static path_object_script path_object_shared path_object_static path_program_script path_program_shared path_program_static path_sources path_sources_headers path_sources_library path_sources_object path_sources_program path_sources_script preserve_path_headers process_post process_pre search_exclusive search_shared search_static stage version_file version_major version_major_prefix version_micro version_micro_prefix version_minor version_minor_prefix version_nano version_nano_prefix version_target ; do + + bootstrap_id "${i}" + + if [[ ${key} == "" ]] ; then + if [[ ${verbosity} != "quiet" && ${verbosity} != "error" ]] ; then + echo -e "${c_warning}WARNING: Failed to find index for '${c_notice}${i}${c_warning}' when calling ${c_notice}bootstrap_id()${c_warning}.${c_reset}" + fi + + key= + bootstrap_id "has-${i}" + if [[ ${key} != "" ]] ; then + variables[${key}]="no" + fi + else + if [[ $(grep -sho "^[[:space:]]*${i}[[:space:]].*\$" ${settings_file}) != "" ]] ; then + value=$(grep -sho "^[[:space:]]*${i}[[:space:]].*\$" ${settings_file} | sed -e "s|^[[:space:]]*${i}\>||" -e 's|^[[:space:]]*||') + variables[${key}]="${value}" + + key= + bootstrap_id "has-${i}" + if [[ ${key} != "" ]] ; then + variables[${key}]="yes" + fi + elif [[ $(grep -sho "^[[:space:]]*${i}\$" ${settings_file}) != "" ]] ; then + variables[${key}]="" + + key= + bootstrap_id "has-${i}" + if [[ ${key} != "" ]] ; then + variables[${key}]="yes" + fi + else + key= + bootstrap_id "has-${i}" + if [[ ${key} != "" ]] ; then + variables[${key}]="no" + fi + fi + fi + done + + # Multi value Objects. + for i in build_indexer_arguments build_libraries build_libraries_shared build_libraries_static build_objects_library build_objects_library_shared build_objects_library_static build_objects_program build_objects_program_shared build_objects_program_static build_sources_documentation build_sources_headers build_sources_headers_shared build_sources_headers_static build_sources_library build_sources_library_shared build_sources_library_static build_sources_program build_sources_program_shared build_sources_program_static build_sources_script build_sources_setting defines defines_library defines_library_shared defines_library_static defines_object defines_object_shared defines_object_static defines_program defines_program_shared defines_program_static defines_shared defines_static environment flags flags_library flags_library_shared flags_library_static flags_object flags_object_shared flags_object_static flags_program flags_program_shared flags_program_static flags_shared flags_static ; do + + bootstrap_id "${i}" + + if [[ ${key} == "" ]] ; then + if [[ ${verbosity} != "quiet" && ${verbosity} != "error" ]] ; then + echo -e "${c_warning}WARNING: Failed to find index for '${c_notice}${i}${c_warning}' when calling ${c_notice}bootstrap_id()${c_warning}.${c_reset}" + fi + + key= + bootstrap_id "has-${i}" + if [[ ${key} != "" ]] ; then + variables[${key}]="no" + fi + else + if [[ $(grep -sho "^[[:space:]]*${i}[[:space:]].*\$" ${settings_file}) != "" ]] ; then + value=$(grep -sho "^[[:space:]]*${i}[[:space:]].*\$" ${settings_file} | sed -e "s|^[[:space:]]*${i}\>||" -e 's|^[[:space:]]*||') + variables[${key}]="${variables[${key}]}${value} " + + key= + bootstrap_id "has-${i}" + if [[ ${key} != "" ]] ; then + variables[${key}]="yes" + fi + elif [[ $(grep -sho "^[[:space:]]*${i}\$" ${settings_file}) != "" ]] ; then + variables[${key}]="" + + key= + bootstrap_id "has-${i}" + if [[ ${key} != "" ]] ; then + variables[${key}]="yes" + fi + else + key= + bootstrap_id "has-${i}" + if [[ ${key} != "" ]] ; then + variables[${key}]="no" + fi + fi + fi + done +} + +bootstrap_load_settings_mode() { + local i= + local key= + local m= + local value= + + for m in ${modes} ; do + + # Single value Objects. + for i in build_compiler build_indexer build_language build_name build_script build_shared build_sources_object build_sources_object_shared build_sources_object_static build_static has_path_standard path_headers path_language path_library_script path_library_shared path_library_static path_object_script path_object_shared path_object_static path_program_script path_program_shared path_program_static path_sources path_sources_headers path_sources_library path_sources_object path_sources_program path_sources_script preserve_path_headers process_post process_pre search_exclusive search_shared search_static stage version_file version_major version_major_prefix version_micro version_micro_prefix version_minor version_minor_prefix version_nano version_nano_prefix version_target ; do + + bootstrap_id "${i}-mode" + + if [[ ${key} == "" ]] ; then + if [[ ${verbosity} != "quiet" && ${verbosity} != "error" ]] ; then + echo -e "${c_warning}WARNING: Failed to find index for '${c_notice}${i}-${m}${c_warning}' when calling ${c_notice}bootstrap_id()${c_warning}.${c_reset}" + fi + + key= + bootstrap_id "has-${i}-mode" + if [[ ${key} != "" ]] ; then + variables[${key}]="no" + fi + else + + if [[ $(grep -sho "^[[:space:]]*${i}-${m}[[:space:]].*\$" ${settings_file}) != "" ]] ; then + value=$(grep -sho "^[[:space:]]*${i}-${m}[[:space:]].*\$" ${settings_file} | sed -e "H;/${i}-${m}/h;\$!d;x" | sed -e "s|^[[:space:]]*${i}-${m}\>||" -e 's|^[[:space:]]*||') + variables[${key}]="${value}" + + key= + bootstrap_id "has-${i}-mode" + if [[ ${key} != "" ]] ; then + variables[${key}]="yes" + fi + elif [[ $(grep -sho "^[[:space:]]*${i}-${m}\$" ${settings_file}) != "" ]] ; then + variables[${key}]="" + + key= + bootstrap_id "has-${i}-mode" + if [[ ${key} != "" ]] ; then + variables[${key}]="yes" + fi + else + key= + bootstrap_id "has-${i}-mode" + if [[ ${key} != "" ]] ; then + variables[${key}]="no" + fi + fi + fi + done + + # Multi value Objects. + for i in build_indexer_arguments build_libraries build_libraries_shared build_libraries_static build_objects_library build_objects_library_shared build_objects_library_static build_objects_program build_objects_program_shared build_objects_program_static build_sources_documentation build_sources_headers build_sources_headers_shared build_sources_headers_static build_sources_library build_sources_library_shared build_sources_library_static build_sources_object_shared build_sources_object_static build_sources_program build_sources_program_shared build_sources_program_static build_sources_script build_sources_setting build_static defines defines_library defines_library_shared defines_library_static defines_object defines_object_shared defines_object_static defines_program defines_program_shared defines_program_static defines_shared defines_static environment flags flags_library flags_library_shared flags_library_static flags_object flags_object_shared flags_object_static flags_program flags_program_shared flags_program_static flags_shared flags_static ; do + + bootstrap_id "${i}-mode" + + if [[ ${key} == "" ]] ; then + if [[ ${verbosity} != "quiet" && ${verbosity} != "error" ]] ; then + echo -e "${c_warning}WARNING: Failed to find index for '${c_notice}${i}-${m}${c_warning}' when calling ${c_notice}bootstrap_id()${c_warning}.${c_reset}" + fi + + key= + bootstrap_id "has-${i}-mode" + if [[ ${key} != "" ]] ; then + variables[${key}]="no" + fi + else + if [[ $(grep -sho "^[[:space:]]*${i}-${m}[[:space:]].*\$" ${settings_file}) != "" ]] ; then + value=$(grep -sho "^[[:space:]]*${i}-${m}[[:space:]].*\$" ${settings_file} | sed -e "s|^[[:space:]]*${i}-${m}\>||" -e 's|^[[:space:]]*||') + variables[${key}]="${variables[${key}]}${value} " + + key= + bootstrap_id "has-${i}" + if [[ ${key} != "" ]] ; then + variables[${key}]="yes" + fi + elif [[ $(grep -sho "^[[:space:]]*${i}-${m}\$" ${settings_file}) != "" ]] ; then + variables[${key}]="" + + key= + bootstrap_id "has-${i}" + if [[ ${key} != "" ]] ; then + variables[${key}]="yes" + fi + else + key= + bootstrap_id "has-${i}-mode" + if [[ ${key} != "" && ${variables[${key}]} != "yes" ]] ; then + variables[${key}]="no" + fi + fi + fi + done + done +} + +bootstrap_prepare_build() { + local alt=${1} + local i= + + mkdir ${verbose_common} -p ${path_build}{documents,documentation,includes,libraries/{script,shared,static},objects/{script,shared,static},programs/{script,shared,static},settings,stage} || failure=1 + + if [[ ${failure} -eq 1 ]] ; then + if [[ ${verbosity} != "quiet" && ${verbosity} != "error" ]] ; then + echo -e "${c_warning}WARNING: Failed to create build directories in '${c_notice}${path_build}${c_error}'.${c_reset}" + fi + + return 1 + fi + + bootstrap_id "path_headers-mode" + if [[ ${variables[${key}]} != "" ]] ; then + mkdir ${verbose_common} -p ${path_build}includes/${variables[${key}]} || failure=1 + else + bootstrap_id "path_headers" + + if [[ ${variables[${key}]} != "" ]] ; then + mkdir ${verbose_common} -p ${path_build}includes/${variables[${key}]} || failure=1 + fi + fi + + if [[ ${failure} -eq 1 ]] ; then + if [[ ${verbosity} != "quiet" && ${verbosity} != "error" ]] ; then + echo -e "${c_warning}WARNING: Failed to create ${c_notice}path_heades${c_error} build directories in '${c_notice}${path_build}${c_error}'.${c_reset}" + fi + + return 1 + fi + + touch ${project_built}-${settings_name}.prepared + + if [[ ${failure} -eq 1 ]] ; then + return 1 + fi + + return 0 +} + +bootstrap_operation_build() { + local i= + local n= + local version_file= + local version_target= + local alt=${1} + local directory= + local key= + + bootstrap_id "build_compiler" + local build_compiler=${variables[${key}]} + + bootstrap_id "build_indexer" + local build_indexer=${variables[${key}]} + + bootstrap_id "build_indexer_arguments" + local build_indexer_arguments=${variables[${key}]} + + bootstrap_id "build_name" + local build_name=${variables[${key}]} + + bootstrap_id "build_shared" + local build_shared=${variables[${key}]} + + bootstrap_id "build_static" + local build_static=${variables[${key}]} + + bootstrap_id "defines" + local defines=${variables[${key}]} + + bootstrap_id "defines_library" + local defines_library=${variables[${key}]} + + bootstrap_id "defines_library_shared" + local defines_library_shared=${variables[${key}]} + + bootstrap_id "defines_library_static" + local defines_library_static=${variables[${key}]} + + bootstrap_id "defines_object" + local defines_object=${variables[${key}]} + + bootstrap_id "defines_object_shared" + local defines_object_shared=${variables[${key}]} + + bootstrap_id "defines_object_static" + local defines_object_static=${variables[${key}]} + + bootstrap_id "defines_program" + local defines_program=${variables[${key}]} + + bootstrap_id "defines_program_shared" + local defines_program_shared=${variables[${key}]} + + bootstrap_id "defines_program_static" + local defines_program_static=${variables[${key}]} + + bootstrap_id "defines_shared" + local defines_shared=${variables[${key}]} + + bootstrap_id "defines_static" + local defines_static=${variables[${key}]} + + bootstrap_id "flags" + local flags=${variables[${key}]} + + bootstrap_id "flags_library" + local flags_library=${variables[${key}]} + + bootstrap_id "flags_library_shared" + local flags_library_shared=${variables[${key}]} + + bootstrap_id "flags_library_static" + local flags_library_static=${variables[${key}]} + + bootstrap_id "flags_object" + local flags_object=${variables[${key}]} + + bootstrap_id "flags_object_shared" + local flags_object_shared=${variables[${key}]} + + bootstrap_id "flags_object_static" + local flags_object_static=${variables[${key}]} + + bootstrap_id "flags_program" + local flags_program=${variables[${key}]} + + bootstrap_id "flags_program_shared" + local flags_program_shared=${variables[${key}]} + + bootstrap_id "flags_program_static" + local flags_program_static=${variables[${key}]} + + bootstrap_id "flags_shared" + local flags_shared=${variables[${key}]} + + bootstrap_id "flags_static" + local flags_static=${variables[${key}]} + + bootstrap_id "build_libraries" + local libraries=${variables[${key}]} + + bootstrap_id "build_libraries_shared" + local libraries_shared=${variables[${key}]} + + bootstrap_id "build_libraries_static" + local libraries_static=${variables[${key}]} + + bootstrap_id "build_objects_library" + local objects_library=${variables[${key}]} + + bootstrap_id "build_objects_library_shared" + local objects_library_shared=${variables[${key}]} + + bootstrap_id "build_objects_library_static" + local objects_library_static=${variables[${key}]} + + bootstrap_id "build_objects_program" + local objects_program=${variables[${key}]} + + bootstrap_id "build_objects_program_shared" + local objects_program_shared=${variables[${key}]} + + bootstrap_id "build_objects_program_static" + local objects_program_static=${variables[${key}]} + + bootstrap_id "path_headers" + local path_headers=${variables[${key}]} + + bootstrap_id "preserve_path_headers" + local preserve_path_headers=${variables[${key}]} + + bootstrap_id "path_library_script" + local path_library_script=${variables[${key}]} + + bootstrap_id "path_library_shared" + local path_library_shared=${variables[${key}]} + + bootstrap_id "path_library_static" + local path_library_static=${variables[${key}]} + + bootstrap_id "path_object_script" + local path_object_script=${variables[${key}]} + + bootstrap_id "path_object_shared" + local path_object_shared=${variables[${key}]} + + bootstrap_id "path_object_static" + local path_object_static=${variables[${key}]} + + bootstrap_id "path_program_script" + local path_program_script=${variables[${key}]} + + bootstrap_id "path_program_shared" + local path_program_shared=${variables[${key}]} + + bootstrap_id "path_program_static" + local path_program_static=${variables[${key}]} + + bootstrap_id "path_sources_headers" + local path_sources_headers=${variables[${key}]} + + bootstrap_id "path_sources_library" + local path_sources_library=${variables[${key}]} + + bootstrap_id "path_sources_object" + local path_sources_object=${variables[${key}]} + + bootstrap_id "path_sources_program" + local path_sources_program=${variables[${key}]} + + bootstrap_id "path_sources_script" + local path_sources_script=${variables[${key}]} + + bootstrap_id "has_path_standard" + local has_path_standard=${variables[${key}]} + + bootstrap_id "search_exclusive" + local search_exclusive=${variables[${key}]} + + bootstrap_id "search_shared" + local search_shared=${variables[${key}]} + + bootstrap_id "search_static" + local search_static=${variables[${key}]} + + bootstrap_id "build_sources_documentation" + local sources_documentation=${variables[${key}]} + + bootstrap_id "build_sources_headers" + local sources_headers=${variables[${key}]} + + bootstrap_id "build_sources_library" + local sources_library=${variables[${key}]} + + bootstrap_id "build_sources_library_shared" + local sources_library_shared=${variables[${key}]} + + bootstrap_id "build_sources_library_static" + local sources_library_static=${variables[${key}]} + + bootstrap_id "build_sources_object" + local sources_object=${variables[${key}]} + + bootstrap_id "build_sources_object_shared" + local sources_object_shared=${variables[${key}]} + + bootstrap_id "build_sources_object_static" + local sources_object_static=${variables[${key}]} + + bootstrap_id "build_sources_program" + local sources_program=${variables[${key}]} + + bootstrap_id "build_sources_program_shared" + local sources_program_shared=${variables[${key}]} + + bootstrap_id "build_sources_program_static" + local sources_program_static=${variables[${key}]} + + bootstrap_id "build_sources_script" + local sources_script=${variables[${key}]} + + bootstrap_id "build_sources_setting" + local sources_setting=${variables[${key}]} + + bootstrap_id "version_file" + local version_file_value=${variables[${key}]} + + bootstrap_id "version_major" + local version_major=${variables[${key}]} + + bootstrap_id "version_major_prefix" + local version_major_prefix=${variables[${key}]} + + bootstrap_id "version_minor" + local version_minor=${variables[${key}]} + + bootstrap_id "version_minor_prefix" + local version_minor_prefix=${variables[${key}]} + + bootstrap_id "version_micro" + local version_micro=${variables[${key}]} + + bootstrap_id "version_micro_prefix" + local version_micro_prefix=${variables[${key}]} + + bootstrap_id "version_nano" + local version_nano=${variables[${key}]} + + bootstrap_id "version_nano_prefix" + local version_nano_prefix=${variables[${key}]} + + bootstrap_id "version_target" + local version_target_value=${variables[${key}]} + + local links= + local sources= + + bootstrap_operation_build_prepare_defaults + + bootstrap_operation_build_prepare_versions + + bootstrap_operation_build_prepare_shared_static + + bootstrap_operation_build_prepare_paths + + bootstrap_operation_build_prepare_flags + + bootstrap_operation_build_prepare_defines + + bootstrap_operation_build_prepare_libraries + + bootstrap_operation_build_prepare_objects + + bootstrap_operation_build_prepare_programs + + bootstrap_operation_build_prepare_settings + + bootstrap_operation_build_prepare_documentation + + bootstrap_operation_build_prepare_headers + + bootstrap_operation_build_prepare_remaining + + local arguments_include="-I${path_build}includes/" + local arguments_shared="-L${path_build}libraries/${path_library_shared}" + local arguments_static="-L${path_build}libraries/${path_library_static}" + + if [[ ${path_work} != "" ]] ; then + arguments_include="${arguments_include} -I${path_work}includes/" + arguments_shared="${arguments_shared} -L${path_work}libraries/${path_library_shared}" + arguments_static="${arguments_static} -L${path_work}libraries/${path_library_static}" + fi + + bootstrap_operation_build_validate_paths + + bootstrap_operation_build_validate_shared_static + + bootstrap_operation_build_validate_sources + + bootstrap_operation_build_validate_search + + bootstrap_operation_build_validate_build + + if [[ ${failure} -eq 1 ]] ; then + return 1 + fi + + if [[ ${sources_documentation} != "" ]] ; then + for i in ${sources_documentation} ; do + + directory=$(dirname ${i}) + if [[ ${directory} == "." ]] ; then + directory= + elif [[ ${directory} != "" ]] ; then + directory="${directory}/" + fi + + if [[ ! -e ${path_documentation}${i} ]] ; then + if [[ ${verbosity} != "quiet" && ${verbosity} != "error" ]] ; then + echo + echo -e "${c_warning}WARNING: Documentation path '${c_notice}${path_documentation}${i}${c_warning}' is not found.${c_reset}" + fi + + continue; + fi + + if [[ ! -d ${path_build}documentation/${directory} ]] ; then + mkdir ${verbose_common} -p ${path_build}documentation/${directory} || failure=1 + fi + + if [[ ${failure} -eq 0 ]] ; then + cp ${verbose_common} -R ${path_documentation}${i} ${path_build}documentation/${directory} || failure=1 + fi + done + fi + + if [[ ${sources_setting} != "" ]] ; then + for i in ${sources_setting} ; do + + directory=$(dirname ${i}) + if [[ ${directory} == "." ]] ; then + directory= + elif [[ ${directory} != "" ]] ; then + directory="${directory}/" + fi + + if [[ ! -d ${path_build}settings/${directory} ]] ; then + mkdir ${verbose_common} -p ${path_build}settings/${directory} || failure=1 + fi + + if [[ ${failure} -eq 0 ]] ; then + cp ${verbose_common} -R ${path_settings}${i} ${path_build}settings/${directory} || failure=1 + fi + done + fi + + if [[ ${failure} -eq 0 && ${sources_headers} != "" ]] ; then + if [[ ${preserve_path_headers} == "yes" ]] ; then + for i in ${sources_headers} ; do + + directory=$(dirname ${i}) + if [[ ${directory} == "." ]] ; then + directory= + elif [[ ${directory} != "" ]] ; then + directory="${directory}/" + fi + + if [[ ! -d ${path_build}includes/${path_headers}${directory} ]] ; then + mkdir ${verbose_common} -p ${path_build}includes/${path_headers}${directory} || failure=1 + fi + + if [[ ${failure} -eq 0 ]] ; then + cp ${verbose_common} -f ${path_sources_headers}${path_language}${i} ${path_build}includes/${path_headers}${directory} || failure=1 + fi + done + else + for i in ${sources_headers} ; do + cp ${verbose_common} -f ${path_sources_headers}${path_language}${i} ${path_build}includes/${path_headers} || failure=1 + done + fi + fi + + if [[ ${failure} -eq 0 && ${build_shared} == "yes" && ! -f ${project_built_shared}-${settings_name}.built ]] ; then + if [[ ${sources_object} != "" || ${sources_object_shared} != "" ]] ; then + for i in ${sources_object} ${sources_object_shared} ; do + + directory=$(dirname ${i}) + if [[ ${directory} == "." ]] ; then + directory= + elif [[ ${directory} != "" ]] ; then + directory="${directory}/" + fi + + if [[ ! -d ${path_build}objects/${path_object_shared}${directory} ]] ; then + mkdir ${verbose_common} -p ${path_build}objects/${path_object_shared}${directory} || failure=1 + fi + + sources="${path_sources_object}${path_language}${i} " + n=$(sed -e 's|\.[^\.]*$||' <<< ${i}) + + if [[ ${verbosity} == "verbose" ]] ; then + echo ${build_compiler} ${sources} -c -o ${path_build}objects/${path_object_shared}${n}.o ${arguments_shared} ${arguments_include} ${libraries} ${libraries_shared} ${flags} ${flags_shared} ${flags_object} ${flags_object_shared} ${defines} ${defines_shared} ${defines_object} ${defines_object_shared} ${define_extra} + fi + + ${build_compiler} ${sources} -c -o ${path_build}objects/${path_object_shared}${n}.o ${arguments_shared} ${arguments_include} ${libraries} ${libraries_shared} ${flags} ${flags_shared} ${flags_object} ${flags_object_shared} ${defines} ${defines_shared} ${defines_object} ${defines_object_shared} ${define_extra} || failure=1 + + if [[ ${failure} -ne 0 ]] ; then + break + fi + done + fi + + if [[ ${failure} -eq 0 && (${sources_library} != "" || ${sources_library_shared} != "") ]] ; then + sources= + + if [[ ${objects_library} != "" || ${objects_library_shared} != "" ]] ; then + for i in ${objects_library} ${objects_library_shared} ; do + sources="${sources}${path_build}objects/${path_object_shared}${i} " + done + fi + + for i in ${sources_library} ${sources_library_shared} ; do + sources="${sources}${path_sources_library}${path_language}${i} " + done + + if [[ ${verbosity} == "verbose" ]] ; then + echo ${build_compiler} ${sources} -shared -Wl,-soname,lib${build_name}.so${version_target} -o ${path_build}libraries/${path_library_shared}lib${build_name}.so${version_file} ${arguments_shared} ${arguments_include} ${libraries} ${libraries_shared} ${flags} ${flags_shared} ${flags_library} ${flags_library_shared} ${defines} ${defines_shared} ${defines_library} ${defines_library_shared} ${define_extra} + fi + + ${build_compiler} ${sources} -shared -Wl,-soname,lib${build_name}.so${version_target} -o ${path_build}libraries/${path_library_shared}lib${build_name}.so${version_file} ${arguments_shared} ${arguments_include} ${libraries} ${libraries_shared} ${flags} ${flags_shared} ${flags_library} ${flags_library_shared} ${defines} ${defines_shared} ${defines_library} ${defines_library_shared} ${define_extra} || failure=1 + + if [[ ${failure} -eq 0 ]] ; then + if [[ ${version_file_value} != "major" ]] ; then + if [[ ${version_file_value} == "minor" ]] ; then + ln ${verbose_common} -sf lib${build_name}.so${version_file} ${path_build}libraries/${path_library_shared}lib${build_name}.so${version_major_prefix}${version_major} || failure=1 + else + ln ${verbose_common} -sf lib${build_name}.so${version_major_prefix}${version_major}${version_minor_prefix}${version_minor} ${path_build}libraries/${path_library_shared}lib${build_name}.so${version_major_prefix}${version_major} || failure=1 + + if [[ ${failure} -eq 0 ]] ; then + if [[ ${version_file_value} == "micro" ]] ; then + ln ${verbose_common} -sf lib${build_name}.so${version_file} ${path_build}libraries/${path_library_shared}lib${build_name}.so${version_major_prefix}${version_major}${version_minor_prefix}${version_minor} || failure=1 + else + ln ${verbose_common} -sf lib${build_name}.so${version_major_prefix}${version_major}${version_minor_prefix}${version_minor}${version_micro_prefix}${version_micro} ${path_build}libraries/${path_library_shared}lib${build_name}.so${version_major_prefix}${version_major}${version_minor_prefix}${version_minor} || failure=1 + + if [[ ${failure} -eq 0 ]] ; then + ln ${verbose_common} -sf lib${build_name}.so${version_file} ${path_build}libraries/${path_library_shared}lib${build_name}.so${version_major_prefix}${version_major}${version_minor_prefix}${version_minor_prefix}${version_minor}${version_micro_prefix}${version_micro} || failure=1 + fi + fi + fi + fi + fi + + if [[ ${failure} -eq 0 ]] ; then + ln ${verbose_common} -sf lib${build_name}.so${version_major_prefix}${version_major} ${path_build}libraries/${path_library_shared}lib${build_name}.so || failure=1 + fi + fi + fi + + if [[ ${failure} -eq 0 && (${sources_program} != "" || ${sources_program_shared} != "") ]] ; then + sources= + links= + + if [[ ${sources_library} != "" || ${sources_library_shared} != "" ]] ; then + links="-l${build_name} " + fi + + if [[ ${objects_program} != "" || ${objects_program_shared} != "" ]] ; then + for i in ${objects_program} ${objects_program_shared} ; do + sources="${sources}${path_build}objects/${path_object_shared}${i} " + done + fi + + for i in ${sources_program} ${sources_program_shared} ; do + sources="${sources}${path_sources_program}${path_language}${i} " + done + + if [[ ${verbosity} == "verbose" ]] ; then + echo ${build_compiler} ${sources} -o ${path_build}programs/${path_program_shared}${build_name} ${arguments_shared} ${arguments_include} ${links} ${libraries} ${libraries_shared} ${flags} ${flags_shared} ${flags_program} ${flags_program_shared} ${defines} ${defines_shared} ${defines_program} ${defines_program_shared} ${define_extra} + fi + + ${build_compiler} ${sources} -o ${path_build}programs/${path_program_shared}${build_name} ${arguments_shared} ${arguments_include} ${links} ${libraries} ${libraries_shared} ${flags} ${flags_shared} ${flags_program} ${flags_program_shared} ${defines} ${defines_shared} ${defines_program} ${defines_program_shared} ${define_extra} || failure=1 + fi + + if [[ ${failure} -eq 0 ]] ; then + touch ${project_built_shared}-${settings_name}.built + fi + fi + + if [[ ${failure} -eq 0 && ${build_static} == "yes" && ! -f ${project_built_static}-${settings_name}.built ]] ; then + if [[ ${sources_object} != "" || ${sources_object_static} != "" ]] ; then + for i in ${sources_object} ${sources_object_static} ; do + + directory=$(dirname ${i}) + if [[ ${directory} == "." ]] ; then + directory= + elif [[ ${directory} != "" ]] ; then + directory="${directory}/" + fi + + if [[ ! -d ${path_build}objects/${path_object_shared}${directory} ]] ; then + mkdir ${verbose_common} -p ${path_build}objects/${path_object_shared}${directory} || failure=1 + fi + + sources="${path_sources_object}${path_language}${i} " + n=$(sed -e 's|\.[^\.]*$||' <<< ${i}) + + if [[ ${verbosity} == "verbose" ]] ; then + echo ${build_compiler} ${sources} -c -o ${path_build}objects/${path_object_static}${n}.o ${arguments_static} ${arguments_include} ${libraries} ${libraries_static} ${flags} ${flags_static} ${flags_object} ${flags_object_static} ${defines} ${defines_static} ${defines_object} ${defines_object_static} ${define_extra} + fi + + ${build_compiler} ${sources} -c -o ${path_build}objects/${path_object_static}${n}.o ${arguments_static} ${arguments_include} ${libraries} ${libraries_static} ${flags} ${flags_static} ${flags_object} ${flags_object_static} ${defines} ${defines_static} ${defines_object} ${defines_object_static} ${define_extra} || failure=1 + + if [[ ${failure} -ne 0 ]] ; then + break + fi + done + fi + + if [[ ${sources_library} != "" || ${sources_library_static} != "" ]] ; then + sources= + + if [[ ${objects_library} != "" || ${objects_library_static} != "" ]] ; then + for i in ${objects_library} ${objects_library_static} ; do + sources="${sources}${path_build}objects/${path_object_static}${i} " + done + fi + + for i in ${sources_library} ${sources_library_static} ; do + + directory=$(dirname ${i}) + if [[ ${directory} == "." ]] ; then + directory= + elif [[ ${directory} != "" ]] ; then + directory="${directory}/" + fi + + n=$(basename ${i} | sed -e 's|\.[^\.]*$||') + + if [[ ! -d ${path_build}objects/${directory} ]] ; then + mkdir ${verbose_common} -p ${path_build}objects/${directory} || failure=1 + + if [[ ${failure} -eq 1 ]] ; then + break; + fi + fi + + # These are objects created by the static build step rather than objects created by the object build step. + sources="${sources}${path_build}objects/${directory}${n}.o " + + if [[ ${verbosity} == "verbose" ]] ; then + echo ${build_compiler} ${path_sources_library}${path_language}${i} -c -static -o ${path_build}objects/${directory}${n}.o ${arguments_static} ${arguments_include} ${libraries} ${libraries_static} ${flags} ${flags_static} ${flags_library} ${flags_library_static} ${defines} ${defines_static} ${defines_library} ${defines_library_static} ${define_extra} + fi + + ${build_compiler} ${path_sources_library}${path_language}${i} -c -static -o ${path_build}objects/${directory}${n}.o ${arguments_static} ${arguments_include} ${libraries} ${libraries_static} ${flags} ${flags_static} ${flags_library} ${flags_library_static} ${defines} ${defines_static} ${defines_library} ${defines_library_static} ${define_extra} || failure=1 + + if [[ ${failure} -eq 1 ]] ; then + break; + fi + done + + if [[ ${failure} -eq 0 && ( ${sources_library} != "" || ${sources_library_static} != "" ) ]] ; then + + if [[ ${verbosity} == "verbose" ]] ; then + echo ${build_indexer} ${build_indexer_arguments} ${path_build}libraries/${path_library_static}lib${build_name}.a ${sources} + fi + + ${build_indexer} ${build_indexer_arguments} ${path_build}libraries/${path_library_static}lib${build_name}.a ${sources} || failure=1 + fi + fi + + if [[ ${failure} -eq 0 && (${sources_program} != "" || ${sources_program_static} != "") ]] ; then + sources= + links= + + if [[ ${sources_library} != "" || ${sources_library_static} != "" ]] ; then + links="-l${build_name} " + fi + + if [[ ${objects_program} != "" || ${objects_program_static} != "" ]] ; then + for i in ${objects_program} ${objects_program_static} ; do + sources="${sources}${path_build}objects/${path_object_static}${i} " + done + fi + + for i in ${sources_program} ${sources_program_static} ; do + sources="${sources}${path_sources_program}${path_language}${i} " + done + + if [[ ${verbosity} == "verbose" ]] ; then + echo ${build_compiler} ${sources} -static -o ${path_build}programs/${path_program_static}${build_name} ${arguments_static} ${arguments_include} ${links} ${libraries} ${libraries_static} ${flags} ${flags_static} ${flags_program} ${flags_program_static} ${defines} ${defines_static} ${defines_program} ${defines_program_static} ${define_extra} + fi + + ${build_compiler} ${sources} -static -o ${path_build}programs/${path_program_static}${build_name} ${arguments_static} ${arguments_include} ${links} ${libraries} ${libraries_static} ${flags} ${flags_static} ${flags_program} ${flags_program_static} ${defines} ${defines_static} ${defines_program} ${defines_program_static} ${define_extra} || failure=1 + fi + + if [[ ${failure} -eq 0 ]] ; then + touch ${project_built_static}-${settings_name}.built + fi + fi + + if [[ ${failure} -eq 1 ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: Failed to build.${c_reset}" + fi + + let failure=1 + + return 1 + fi + + if [[ ${failure} -eq 1 ]] ; then + return 1 + fi + + return 0 +} + +bootstrap_operation_build_prepare_defaults() { + local key= + + bootstrap_id "has-version_major_prefix-mode" + if [[ ${variables[${key}]} != "yes" ]] ; then + + bootstrap_id "has-version_major_prefix" + if [[ ${variables[${key}]} != "yes" ]] ; then + version_major_prefix="." + fi + fi + + bootstrap_id "has-version_minor_prefix-mode" + if [[ ${variables[${key}]} != "yes" ]] ; then + + bootstrap_id "has-version_minor_prefix" + if [[ ${variables[${key}]} != "yes" ]] ; then + version_minor_prefix="." + fi + fi + + bootstrap_id "has-version_micro_prefix-mode" + if [[ ${variables[${key}]} != "yes" ]] ; then + + bootstrap_id "has-version_micro_prefix" + if [[ ${variables[${key}]} != "yes" ]] ; then + version_micro_prefix="." + fi + fi + + bootstrap_id "has-version_nano_prefix-mode" + if [[ ${variables[${key}]} != "yes" ]] ; then + + bootstrap_id "has-version_nano_prefix" + if [[ ${variables[${key}]} != "yes" ]] ; then + version_nano_prefix="." + fi + fi + + bootstrap_id "has-build_compiler-mode" + if [[ ${variables[${key}]} != "yes" ]] ; then + + bootstrap_id "has-build_compiler" + if [[ ${variables[${key}]} != "yes" ]] ; then + build_compiler="gcc" + fi + fi + + bootstrap_id "has-build_indexer-mode" + if [[ ${variables[${key}]} != "yes" ]] ; then + + bootstrap_id "has-build_indexer" + if [[ ${variables[${key}]} != "yes" ]] ; then + build_indexer="ar" + fi + fi + + bootstrap_id "has-path_library_script-mode" + if [[ ${variables[${key}]} != "yes" ]] ; then + + bootstrap_id "has-path_library_script" + if [[ ${variables[${key}]} != "yes" ]] ; then + path_library_script="script/" + fi + fi + + bootstrap_id "has-path_library_shared-mode" + if [[ ${variables[${key}]} != "yes" ]] ; then + + bootstrap_id "has-path_library_shared" + if [[ ${variables[${key}]} != "yes" ]] ; then + path_library_shared="shared/" + fi + fi + + bootstrap_id "has-path_library_static-mode" + if [[ ${variables[${key}]} != "yes" ]] ; then + + bootstrap_id "has-path_library_static" + if [[ ${variables[${key}]} != "yes" ]] ; then + path_library_static="static/" + fi + fi + + bootstrap_id "has-path_object_script-mode" + if [[ ${variables[${key}]} != "yes" ]] ; then + + bootstrap_id "has-path_object_script" + if [[ ${variables[${key}]} != "yes" ]] ; then + path_object_script="script/" + fi + fi + + bootstrap_id "has-path_object_shared-mode" + if [[ ${variables[${key}]} != "yes" ]] ; then + + bootstrap_id "has-path_object_shared" + if [[ ${variables[${key}]} != "yes" ]] ; then + path_object_shared="shared/" + fi + fi + + bootstrap_id "has-path_object_static-mode" + if [[ ${variables[${key}]} != "yes" ]] ; then + + bootstrap_id "has-path_object_static" + if [[ ${variables[${key}]} != "yes" ]] ; then + path_object_static="static/" + fi + fi + + bootstrap_id "has-path_program_script-mode" + if [[ ${variables[${key}]} != "yes" ]] ; then + + bootstrap_id "has-path_program_script" + if [[ ${variables[${key}]} != "yes" ]] ; then + path_program_script="script/" + fi + fi + + bootstrap_id "has-path_program_shared-mode" + if [[ ${variables[${key}]} != "yes" ]] ; then + + bootstrap_id "has-path_program_shared" + if [[ ${variables[${key}]} != "yes" ]] ; then + path_program_shared="shared/" + fi + fi + + bootstrap_id "has-path_program_static-mode" + if [[ ${variables[${key}]} != "yes" ]] ; then + + bootstrap_id "has-path_program_static" + if [[ ${variables[${key}]} != "yes" ]] ; then + path_program_static="static/" + fi + fi + + bootstrap_id "has-path_sources-mode" + if [[ ${variables[${key}]} != "yes" ]] ; then + + bootstrap_id "has-path_sources" + if [[ ${variables[${key}]} != "yes" ]] ; then + path_sources="sources/" + fi + fi + + bootstrap_id "has-path_sources_headers-mode" + if [[ ${variables[${key}]} != "yes" ]] ; then + + bootstrap_id "has-path_sources_headers" + if [[ ${variables[${key}]} != "yes" ]] ; then + path_sources_headers=${path_sources} + fi + fi + + bootstrap_id "has-path_sources_library-mode" + if [[ ${variables[${key}]} != "yes" ]] ; then + + bootstrap_id "has-path_sources_library" + if [[ ${variables[${key}]} != "yes" ]] ; then + path_sources_library=${path_sources} + fi + fi + + bootstrap_id "has-path_sources_object-mode" + if [[ ${variables[${key}]} != "yes" ]] ; then + + bootstrap_id "has-path_sources_object" + if [[ ${variables[${key}]} != "yes" ]] ; then + path_sources_object=${path_sources} + fi + fi + + bootstrap_id "has-path_sources_program-mode" + if [[ ${variables[${key}]} != "yes" ]] ; then + + bootstrap_id "has-path_sources_program" + if [[ ${variables[${key}]} != "yes" ]] ; then + path_sources_program=${path_sources} + fi + fi + + bootstrap_id "has-path_sources_script-mode" + if [[ ${variables[${key}]} != "yes" ]] ; then + + bootstrap_id "has-path_sources_script" + if [[ ${variables[${key}]} != "yes" ]] ; then + path_sources_script=${path_sources} + fi + fi + + bootstrap_id "has-has_path_standard-mode" + if [[ ${variables[${key}]} != "yes" ]] ; then + + bootstrap_id "has-has_path_standard" + if [[ ${variables[${key}]} != "yes" ]] ; then + has_path_standard="yes" + fi + fi + + bootstrap_id "has-search_shared-mode" + if [[ ${variables[${key}]} != "yes" ]] ; then + + bootstrap_id "has-search_shared" + if [[ ${variables[${key}]} != "yes" ]] ; then + search_shared="yes" + fi + fi + + bootstrap_id "has-build_shared-mode" + if [[ ${variables[${key}]} != "yes" ]] ; then + + bootstrap_id "has-build_shared" + if [[ ${variables[${key}]} != "yes" ]] ; then + build_shared="yes" + fi + fi +} + +bootstrap_operation_build_prepare_defines() { + local key= + + bootstrap_id "defines-mode" + if [[ ${defines} == "" ]] ; then + defines=${variables[${key}]} + else + defines="${defines} ${variables[${key}]}" + fi + + bootstrap_id "defines_library-mode" + if [[ ${defines_library} == "" ]] ; then + defines_library=${variables[${key}]} + else + defines_library="${defines_library} ${variables[${key}]}" + fi + + bootstrap_id "defines_library_shared-mode" + if [[ ${defines_library_shared} == "" ]] ; then + defines_library_shared=${variables[${key}]} + else + defines_library_shared="${defines_library_shared} ${variables[${key}]}" + fi + + bootstrap_id "defines_library_static-mode" + if [[ ${defines_library_static} == "" ]] ; then + defines_library_static=${variables[${key}]} + else + defines_library_static="${defines_library_static} ${variables[${key}]}" + fi + + bootstrap_id "defines_object_library-mode" + if [[ ${defines_object_library} == "" ]] ; then + defines_object_library=${variables[${key}]} + else + defines_object_library="${defines_object_library} ${variables[${key}]}" + fi + + bootstrap_id "defines_object_library_shared-mode" + if [[ ${defines_object_library_shared} == "" ]] ; then + defines_object_library_shared=${variables[${key}]} + else + defines_object_library_shared="${defines_object_library_shared} ${variables[${key}]}" + fi + + bootstrap_id "defines_object_library_static-mode" + if [[ ${defines_object_library_static} == "" ]] ; then + defines_object_library_static=${variables[${key}]} + else + defines_object_library_static="${defines_object_library_static} ${variables[${key}]}" + fi + + bootstrap_id "defines_object_program-mode" + if [[ ${defines_object_program} == "" ]] ; then + defines_object_program=${variables[${key}]} + else + defines_object_program="${defines_object_program} ${variables[${key}]}" + fi + + bootstrap_id "defines_object_program_shared-mode" + if [[ ${defines_object_program_shared} == "" ]] ; then + defines_object_program_shared=${variables[${key}]} + else + defines_object_program_shared="${defines_object_program_shared} ${variables[${key}]}" + fi + + bootstrap_id "defines_object_program_static-mode" + if [[ ${defines_object_program_static} == "" ]] ; then + defines_object_program_static=${variables[${key}]} + else + defines_object_program_static="${defines_object_program_static} ${variables[${key}]}" + fi + + bootstrap_id "defines_program-mode" + if [[ ${defines_program} == "" ]] ; then + defines_program=${variables[${key}]} + else + defines_program="${defines_program} ${variables[${key}]}" + fi + + bootstrap_id "defines_program_shared-mode" + if [[ ${defines_program_shared} == "" ]] ; then + defines_program_shared=${variables[${key}]} + else + defines_program_shared="${defines_program_shared} ${variables[${key}]}" + fi + + bootstrap_id "defines_program_static-mode" + if [[ ${defines_program_static} == "" ]] ; then + defines_program_static=${variables[${key}]} + else + defines_program_static="${defines_program_static} ${variables[${key}]}" + fi + + bootstrap_id "defines_shared-mode" + if [[ ${defines_shared} == "" ]] ; then + defines_shared=${variables[${key}]} + else + defines_shared="${defines_shared} ${variables[${key}]}" + fi + + bootstrap_id "defines_static-mode" + if [[ ${defines_static} == "" ]] ; then + defines_static=${variables[${key}]} + else + defines_static="${defines_static} ${variables[${key}]}" + fi +} + +bootstrap_operation_build_prepare_documentation() { + local key= + + bootstrap_id "build_sources_documentation-mode" + if [[ ${sources_documentation} == "" ]] ; then + sources_documentation=${variables[${key}]} + else + sources_documentation="${sources_documentation} ${variables[${key}]}" + fi +} + +bootstrap_operation_build_prepare_flags() { + local key= + + bootstrap_id "flags-mode" + if [[ ${flags} == "" ]] ; then + flags=${variables[${key}]} + else + flags="${flags} ${variables[${key}]}" + fi + + bootstrap_id "flags_library-mode" + if [[ ${flags_library} == "" ]] ; then + flags_library=${variables[${key}]} + else + flags_library="${flags_library} ${variables[${key}]}" + fi + + bootstrap_id "flags_library_shared-mode" + if [[ ${flags_library_shared} == "" ]] ; then + flags_library_shared=${variables[${key}]} + else + flags_library_shared="${flags_library_shared} ${variables[${key}]}" + fi + + bootstrap_id "flags_library_static-mode" + if [[ ${flags_library_static} == "" ]] ; then + flags_library_static=${variables[${key}]} + else + flags_library_static="${flags_library_static} ${variables[${key}]}" + fi + + bootstrap_id "flags_object_library-mode" + if [[ ${flags_object_library} == "" ]] ; then + flags_object_library=${variables[${key}]} + else + flags_object_library="${flags_object_library} ${variables[${key}]}" + fi + + bootstrap_id "flags_object_library_shared-mode" + if [[ ${flags_object_library_shared} == "" ]] ; then + flags_object_library_shared=${variables[${key}]} + else + flags_object_library_shared="${flags_object_library_shared} ${variables[${key}]}" + fi + + bootstrap_id "flags_object_library_static-mode" + if [[ ${flags_object_library_static} == "" ]] ; then + flags_object_library_static=${variables[${key}]} + else + flags_object_library_static="${flags_object_library_static} ${variables[${key}]}" + fi + + bootstrap_id "flags_object_program-mode" + if [[ ${flags_object_program} == "" ]] ; then + flags_object_program=${variables[${key}]} + else + flags_object_program="${flags_object_program} ${variables[${key}]}" + fi + + bootstrap_id "flags_object_program_shared-mode" + if [[ ${flags_object_program_shared} == "" ]] ; then + flags_object_program_shared=${variables[${key}]} + else + flags_object_program_shared="${flags_object_program_shared} ${variables[${key}]}" + fi + + bootstrap_id "flags_object_program_static-mode" + if [[ ${flags_object_program_static} == "" ]] ; then + flags_object_program_static=${variables[${key}]} + else + flags_object_program_static="${flags_object_program_static} ${variables[${key}]}" + fi + + bootstrap_id "flags_program-mode" + if [[ ${flags_program} == "" ]] ; then + flags_program=${variables[${key}]} + else + flags_program="${flags_program} ${variables[${key}]}" + fi + + bootstrap_id "flags_program_shared-mode" + if [[ ${flags_program_shared} == "" ]] ; then + flags_program_shared=${variables[${key}]} + else + flags_program_shared="${flags_program_shared} ${variables[${key}]}" + fi + + bootstrap_id "flags_program_static-mode" + if [[ ${flags_program_static} == "" ]] ; then + flags_program_static=${variables[${key}]} + else + flags_program_static="${flags_program_static} ${variables[${key}]}" + fi + + bootstrap_id "flags_shared-mode" + if [[ ${flags_shared} == "" ]] ; then + flags_shared=${variables[${key}]} + else + flags_shared="${flags_shared} ${variables[${key}]}" + fi + + bootstrap_id "flags_static-mode" + if [[ ${flags_static} == "" ]] ; then + flags_static=${variables[${key}]} + else + flags_static="${flags_static} ${variables[${key}]}" + fi +} + +bootstrap_operation_build_prepare_headers() { + local key= + + bootstrap_id "build_sources_headers-mode" + if [[ ${sources_headers} == "" ]] ; then + sources_headers=${variables[${key}]} + else + sources_headers="${sources_headers} ${variables[${key}]}" + fi + + if [[ ${build_shared} == "yes" ]] ; then + bootstrap_id "build_sources_headers_shared" + if [[ ${sources_headers} == "" ]] ; then + sources_headers=${variables[${key}]} + else + sources_headers="${sources_headers} ${variables[${key}]}" + fi + + bootstrap_id "build_sources_headers_static" + if [[ ${sources_headers} == "" ]] ; then + sources_headers=${variables[${key}]} + else + sources_headers="${sources_headers} ${variables[${key}]}" + fi + fi + + if [[ ${build_static} == "yes" ]] ; then + bootstrap_id "build_sources_headers_shared-mode" + if [[ ${sources_headers} == "" ]] ; then + sources_headers=${variables[${key}]} + else + sources_headers="${sources_headers} ${variables[${key}]}" + fi + + bootstrap_id "build_sources_headers_static-mode" + if [[ ${sources_headers} == "" ]] ; then + sources_headers=${variables[${key}]} + else + sources_headers="${sources_headers} ${variables[${key}]}" + fi + fi + + bootstrap_id "path_headers-mode" + if [[ ${variables[${key}]} != "" ]] ; then + path_headers=${variables[${key}]} + else + bootstrap_id "path_headers" + if [[ ${variables[${key}]} != "" ]] ; then + path_headers=${variables[${key}]} + fi + fi + + if [[ ${path_headers} != "" ]] ; then + path_headers=$(sed -e 's|/*$|/|' <<< ${path_headers}) + fi +} + +bootstrap_operation_build_prepare_libraries() { + local key= + + bootstrap_id "build_libraries-mode" + if [[ ${libraries} == "" ]] ; then + libraries=${variables[${key}]} + else + libraries="${variables[${key}]} ${libraries}" + fi + + bootstrap_id "build_libraries_shared-mode" + if [[ ${libraries_shared} == "" ]] ; then + libraries_shared=${variables[${key}]} + else + libraries_shared="${variables[${key}]} ${libraries_shared}" + fi + + bootstrap_id "build_libraries_static-mode" + if [[ ${libraries_static} == "" ]] ; then + libraries_static=${variables[${key}]} + else + libraries_static="${variables[${key}]} ${libraries_static}" + fi + + bootstrap_id "build_sources_library-mode" + if [[ ${sources_library} == "" ]] ; then + sources_library=${variables[${key}]} + else + sources_library="${sources_library} ${variables[${key}]}" + fi + + bootstrap_id "build_sources_library_shared-mode" + if [[ ${sources_library_shared} == "" ]] ; then + sources_library_shared=${variables[${key}]} + else + sources_library_shared="${build_sources_library_shared} ${variables[${key}]}" + fi + + bootstrap_id "build_sources_library_static-mode" + if [[ ${sources_library_static} == "" ]] ; then + sources_library_static=${variables[${key}]} + else + sources_library_static="${build_sources_library_static} ${variables[${key}]}" + fi +} + +bootstrap_operation_build_prepare_objects() { + local key= + + bootstrap_id "build_objects_library-mode" + if [[ ${objects_library} == "" ]] ; then + objects_library=${variables[${key}]} + else + objects_library="${variables[${key}]} ${objects_library}" + fi + + bootstrap_id "build_objects_library_shared-mode" + if [[ ${objects_library_shared} == "" ]] ; then + objects_library_shared=${variables[${key}]} + else + objects_library_shared="${variables[${key}]} ${objects_library_shared}" + fi + + bootstrap_id "build_objects_library_static-mode" + if [[ ${objects_library_static} == "" ]] ; then + objects_library_static=${variables[${key}]} + else + objects_library_static="${variables[${key}]} ${objects_library_static}" + fi + + bootstrap_id "build_objects_program-mode" + if [[ ${objects_program} == "" ]] ; then + objects_program=${variables[${key}]} + else + objects_program="${variables[${key}]} ${objects_program}" + fi + + bootstrap_id "build_objects_program_shared-mode" + if [[ ${objects_program_shared} == "" ]] ; then + objects_program_shared=${variables[${key}]} + else + objects_program_shared="${variables[${key}]} ${objects_program_shared}" + fi + + bootstrap_id "build_objects_program_static-mode" + if [[ ${objects_program_static} == "" ]] ; then + objects_program_static=${variables[${key}]} + else + objects_program_static="${variables[${key}]} ${objects_program_static}" + fi + + if [[ ${sources_object} == "" ]] ; then + bootstrap_id "build_sources_object-mode" + sources_object=${variables[${key}]} + fi + + if [[ ${sources_object_shared} == "" ]] ; then + bootstrap_id "build_sources_object_shared-mode" + sources_object_shared=${variables[${key}]} + fi + + if [[ ${sources_object_static} == "" ]] ; then + bootstrap_id "build_sources_object_static-mode" + sources_object_static=${variables[${key}]} + fi +} + +bootstrap_operation_build_prepare_paths() { + local key= + + if [[ ${override_path_sources} == "" ]] ; then + bootstrap_id "path_sources-mode" + if [[ ${variables[${key}]} != "" ]] ; then + path_sources=${variables[${key}]} + else + bootstrap_id "path_sources" + if [[ ${variables[${key}]} != "" ]] ; then + path_sources=${variables[${key}]} + fi + fi + fi + + if [[ ${path_sources} != "" ]] ; then + path_sources=$(sed -e 's|//*|/|g' -e 's|/*$|/|' <<< ${path_sources}) + fi + + bootstrap_id "path_sources_object-mode" + if [[ ${variables[${key}]} != "" ]] ; then + path_sources_object=${variables[${key}]} + else + bootstrap_id "path_sources_object" + if [[ ${variables[${key}]} != "" ]] ; then + path_sources_object=${variables[${key}]} + fi + fi + + if [[ ${path_sources_object} != "" ]] ; then + path_sources_object=$(sed -e 's|//*|/|g' -e 's|/*$|/|' <<< ${path_sources_object}) + fi + + bootstrap_id "path_headers-mode" + if [[ ${variables[${key}]} != "" ]] ; then + path_headers=${variables[${key}]} + fi + + if [[ ${path_headers} != "" ]] ; then + path_headers=$(sed -e 's|//*|/|g' -e 's|/*$|/|' <<< ${path_headers}) + fi + + bootstrap_id "has_path_standard-mode" + if [[ ${variables[${key}]} != "" ]] ; then + has_path_standard=${variables[${key}]} + fi + + if [[ ${has_path_standard} == "no" ]] ; then + path_language= + else + bootstrap_id "path_language-mode" + if [[ ${variables[${key}]} != "" ]] ; then + path_language=${variables[${key}]} + else + bootstrap_id "path_language" + if [[ ${variables[${key}]} != "" ]] ; then + path_language=${variables[${key}]} + fi + fi + + if [[ ${path_language} != "" ]] ; then + path_language=$(sed -e 's|//*|/|g' -e 's|/*$|/|' <<< ${path_language}) + fi + fi + + bootstrap_id "path_object_library-mode" + if [[ ${variables[${key}]} != "" ]] ; then + path_object_library=${variables[${key}]} + fi + + if [[ ${path_object_library} != "" ]] ; then + path_object_library=$(sed -e 's|//*|/|g' -e 's|/*$|/|' <<< ${path_object_library}) + fi + + bootstrap_id "path_object_program-mode" + if [[ ${variables[${key}]} != "" ]] ; then + path_object_program=${variables[${key}]} + fi + + if [[ ${path_object_program} != "" ]] ; then + path_object_program=$(sed -e 's|//*|/|g' -e 's|/*$|/|' <<< ${path_object_program}) + fi + + bootstrap_id "path_library_script-mode" + if [[ ${variables[${key}]} != "" ]] ; then + path_library_script=${variables[${key}]} + fi + + if [[ ${path_library_script} != "" ]] ; then + path_library_script=$(sed -e 's|//*|/|g' -e 's|/*$|/|' <<< ${path_library_script}) + fi + + bootstrap_id "path_library_shared-mode" + if [[ ${variables[${key}]} != "" ]] ; then + path_library_shared=${variables[${key}]} + fi + + if [[ ${path_library_shared} != "" ]] ; then + path_library_shared=$(sed -e 's|//*|/|g' -e 's|/*$|/|' <<< ${path_library_shared}) + fi + + bootstrap_id "path_library_static-mode" + if [[ ${variables[${key}]} != "" ]] ; then + path_library_static=${variables[${key}]} + fi + + if [[ ${path_library_static} != "" ]] ; then + path_library_static=$(sed -e 's|//*|/|g' -e 's|/*$|/|' <<< ${path_library_static}) + fi + + bootstrap_id "path_object_library_script-mode" + if [[ ${variables[${key}]} != "" ]] ; then + path_object_library_script=${variables[${key}]} + fi + + if [[ ${path_object_library_script} != "" ]] ; then + path_object_library_script=$(sed -e 's|//*|/|g' -e 's|/*$|/|' <<< ${path_object_library_script}) + fi + + bootstrap_id "path_object_library_shared-mode" + if [[ ${variables[${key}]} != "" ]] ; then + path_object_library_shared=${variables[${key}]} + fi + + if [[ ${path_object_library_shared} != "" ]] ; then + path_object_library_shared=$(sed -e 's|//*|/|g' -e 's|/*$|/|' <<< ${path_object_library_shared}) + fi + + bootstrap_id "path_object_library_static-mode" + if [[ ${variables[${key}]} != "" ]] ; then + path_object_library_static=${variables[${key}]} + fi + + if [[ ${path_object_library_static} != "" ]] ; then + path_object_library_static=$(sed -e 's|//*|/|g' -e 's|/*$|/|' <<< ${path_object_library_static}) + fi + + bootstrap_id "path_object_program_script-mode" + if [[ ${variables[${key}]} != "" ]] ; then + path_object_program_script=${variables[${key}]} + fi + + if [[ ${path_object_program_script} != "" ]] ; then + path_object_program_script=$(sed -e 's|//*|/|g' -e 's|/*$|/|' <<< ${path_object_program_script}) + fi + + bootstrap_id "path_object_program_shared-mode" + if [[ ${variables[${key}]} != "" ]] ; then + path_object_program_shared=${variables[${key}]} + fi + + if [[ ${path_object_program_shared} != "" ]] ; then + path_object_program_shared=$(sed -e 's|//*|/|g' -e 's|/*$|/|' <<< ${path_object_program_shared}) + fi + + bootstrap_id "path_object_program_static-mode" + if [[ ${variables[${key}]} != "" ]] ; then + path_object_program_static=${variables[${key}]} + fi + + if [[ ${path_object_program_static} != "" ]] ; then + path_object_program_static=$(sed -e 's|//*|/|g' -e 's|/*$|/|' <<< ${path_object_program_static}) + fi + + bootstrap_id "path_object_script-mode" + if [[ ${variables[${key}]} != "" ]] ; then + path_object_script=${variables[${key}]} + fi + + if [[ ${path_object_script} != "" ]] ; then + path_object_script=$(sed -e 's|//*|/|g' -e 's|/*$|/|' <<< ${path_object_script}) + fi + + bootstrap_id "path_object_shared-mode" + if [[ ${variables[${key}]} != "" ]] ; then + path_object_shared=${variables[${key}]} + fi + + if [[ ${path_object_shared} != "" ]] ; then + path_object_shared=$(sed -e 's|//*|/|g' -e 's|/*$|/|' <<< ${path_object_shared}) + fi + + bootstrap_id "path_object_static-mode" + if [[ ${variables[${key}]} != "" ]] ; then + path_object_static=${variables[${key}]} + fi + + if [[ ${path_object_static} != "" ]] ; then + path_object_static=$(sed -e 's|//*|/|g' -e 's|/*$|/|' <<< ${path_object_static}) + fi + + if [[ ${path_object_static} != "" ]] ; then + path_object_static=$(sed -e 's|//*|/|g' -e 's|/*$|/|' <<< ${path_object_static}) + fi + + bootstrap_id "path_program_script-mode" + if [[ ${variables[${key}]} != "" ]] ; then + path_program_script=${variables[${key}]} + fi + + if [[ ${path_program_script} != "" ]] ; then + path_program_script=$(sed -e 's|//*|/|g' -e 's|/*$|/|' <<< ${path_program_script}) + fi + + bootstrap_id "path_program_shared-mode" + if [[ ${variables[${key}]} != "" ]] ; then + path_program_shared=${variables[${key}]} + fi + + if [[ ${path_program_shared} != "" ]] ; then + path_program_shared=$(sed -e 's|//*|/|g' -e 's|/*$|/|' <<< ${path_program_shared}) + fi + + bootstrap_id "path_program_static-mode" + if [[ ${variables[${key}]} != "" ]] ; then + path_program_static=${variables[${key}]} + fi + + if [[ ${path_program_static} != "" ]] ; then + path_program_static=$(sed -e 's|//*|/|g' -e 's|/*$|/|' <<< ${path_program_static}) + fi + + if [[ ${path_program_static} != "" ]] ; then + path_program_static=$(sed -e 's|//*|/|g' -e 's|/*$|/|' <<< ${path_program_static}) + fi +} + +bootstrap_operation_build_prepare_programs() { + local key= + + bootstrap_id "build_sources_program-mode" + if [[ ${sources_program} == "" ]] ; then + sources_program=${variables[${key}]} + else + sources_program="${sources_program} ${variables[${key}]}" + fi + + bootstrap_id "build_sources_program_shared-mode" + if [[ ${sources_program_shared} == "" ]] ; then + sources_program_shared=${variables[${key}]} + else + sources_program_shared="${sources_program_shared} ${variables[${key}]}" + fi + + bootstrap_id "build_sources_program_static-mode" + if [[ ${sources_program_static} == "" ]] ; then + sources_program_static=${variables[${key}]} + else + sources_program_static="${sources_program_static} ${variables[${key}]}" + fi +} + +bootstrap_operation_build_prepare_remaining() { + local key= + + bootstrap_id "has-build_compiler-mode" + if [[ ${variables[${key}]} == "yes" ]] ; then + bootstrap_id "build_compiler-mode" + build_compiler=${variables[${key}]} + fi + + bootstrap_id "has-build_indexer-mode" + if [[ ${variables[${key}]} == "yes" ]] ; then + bootstrap_id "build_indexer-mode" + build_indexer=${variables[${key}]} + fi + + bootstrap_id "has-build_indexer_arguments-mode" + if [[ ${variables[${key}]} == "yes" ]] ; then + bootstrap_id "build_indexer_arguments-mode" + build_indexer_arguments=${variables[${key}]} + fi + + bootstrap_id "has-build_name-mode" + if [[ ${variables[${key}]} == "yes" ]] ; then + bootstrap_id "build_name-mode" + build_name=${variables[${key}]} + fi + + bootstrap_id "has-version_major-mode" + if [[ ${variables[${key}]} == "yes" ]] ; then + bootstrap_id "version_major-mode" + version_major=${variables[${key}]} + fi + + bootstrap_id "has-version_major_prefix-mode" + if [[ ${variables[${key}]} == "yes" ]] ; then + bootstrap_id "version_major_prefix-mode" + version_major_prefix=${variables[${key}]} + fi + + bootstrap_id "has-version_minor-mode" + if [[ ${variables[${key}]} == "yes" ]] ; then + bootstrap_id "version_minor-mode" + version_minor=${variables[${key}]} + fi + + bootstrap_id "has-version_minor_prefix-mode" + if [[ ${variables[${key}]} == "yes" ]] ; then + bootstrap_id "version_minor_prefix-mode" + version_minor_prefix=${variables[${key}]} + fi + + bootstrap_id "has-version_micro-mode" + if [[ ${variables[${key}]} == "yes" ]] ; then + bootstrap_id "version_micro-mode" + version_micro=${variables[${key}]} + fi + + bootstrap_id "has-version_micro_prefix-mode" + if [[ ${variables[${key}]} == "yes" ]] ; then + bootstrap_id "version_micro_prefix-mode" + version_micro_prefix=${variables[${key}]} + fi + + bootstrap_id "has-version_nano-mode" + if [[ ${variables[${key}]} == "yes" ]] ; then + bootstrap_id "version_nano-mode" + version_nano=${variables[${key}]} + fi + + bootstrap_id "has-version_nano_prefix-mode" + if [[ ${variables[${key}]} == "yes" ]] ; then + bootstrap_id "version_nano_prefix-mode" + version_nano_prefix=${variables[${key}]} + fi + + bootstrap_id "has-path_headers-mode" + if [[ ${variables[${key}]} == "yes" ]] ; then + bootstrap_id "path_headers-mode" + path_headers=${variables[${key}]} + fi + + bootstrap_id "has-preserve_path_headers-mode" + if [[ ${variables[${key}]} == "yes" ]] ; then + bootstrap_id "preserve_path_headers-mode" + preserve_path_headers=${variables[${key}]} + fi + + bootstrap_id "has-path_library_script-mode" + if [[ ${variables[${key}]} == "yes" ]] ; then + bootstrap_id "path_library_script-mode" + path_library_script=${variables[${key}]} + fi + + bootstrap_id "has-path_library_shared-mode" + if [[ ${variables[${key}]} == "yes" ]] ; then + bootstrap_id "path_library_shared-mode" + path_library_shared=${variables[${key}]} + fi + + bootstrap_id "has-path_library_static-mode" + if [[ ${variables[${key}]} == "yes" ]] ; then + bootstrap_id "path_library_static-mode" + path_library_static=${variables[${key}]} + fi + + bootstrap_id "has-path_object_script-mode" + if [[ ${variables[${key}]} == "yes" ]] ; then + bootstrap_id "path_object_script-mode" + path_object_script=${variables[${key}]} + fi + + bootstrap_id "has-path_object_shared-mode" + if [[ ${variables[${key}]} == "yes" ]] ; then + bootstrap_id "path_object_shared-mode" + path_object_shared=${variables[${key}]} + fi + + bootstrap_id "has-path_object_static-mode" + if [[ ${variables[${key}]} == "yes" ]] ; then + bootstrap_id "path_object_static-mode" + path_object_static=${variables[${key}]} + fi + + bootstrap_id "has-path_program_script-mode" + if [[ ${variables[${key}]} == "yes" ]] ; then + bootstrap_id "path_program_script-mode" + path_program_script=${variables[${key}]} + fi + + bootstrap_id "has-path_program_shared-mode" + if [[ ${variables[${key}]} == "yes" ]] ; then + bootstrap_id "path_program_shared-mode" + path_program_shared=${variables[${key}]} + fi + + bootstrap_id "has-path_program_static-mode" + if [[ ${variables[${key}]} == "yes" ]] ; then + bootstrap_id "path_program_static-mode" + path_program_static=${variables[${key}]} + fi + + bootstrap_id "has-has_path_standard-mode" + if [[ ${variables[${key}]} == "yes" ]] ; then + bootstrap_id "has_path_standard-mode" + has_path_standard=${variables[${key}]} + fi + + bootstrap_id "has-search_exclusive-mode" + if [[ ${variables[${key}]} == "yes" ]] ; then + bootstrap_id "search_exclusive-mode" + search_exclusive=${variables[${key}]} + fi + + bootstrap_id "has-search_shared-mode" + if [[ ${variables[${key}]} == "yes" ]] ; then + bootstrap_id "search_shared-mode" + search_shared=${variables[${key}]} + fi + + bootstrap_id "has-search_static-mode" + if [[ ${variables[${key}]} == "yes" ]] ; then + bootstrap_id "search_static-mode" + search_static=${variables[${key}]} + fi + + bootstrap_id "has-stage-mode" + if [[ ${variables[${key}]} == "yes" ]] ; then + bootstrap_id "stage-mode" + stage=${variables[${key}]} + fi +} + +bootstrap_operation_build_prepare_settings() { + local key= + + bootstrap_id "build_sources_setting-mode" + if [[ ${sources_setting} == "" ]] ; then + sources_setting=${variables[${key}]} + else + sources_setting="${sources_setting} ${variables[${key}]}" + fi +} + +bootstrap_operation_build_prepare_shared_static() { + local key= + + bootstrap_id "build_shared-mode" + if [[ ${variables[${key}]} != "" ]] ; then + build_shared=${variables[${key}]} + fi + + bootstrap_id "build_static-mode" + if [[ ${variables[${key}]} != "" ]] ; then + build_static=${variables[${key}]} + fi + + if [[ ${enable_shared} == "yes" ]] ; then + build_shared="yes" + search_shared="yes" + elif [[ ${enable_shared} == "no" ]] ; then + build_shared="no" + search_shared="no" + fi + + if [[ ${enable_static} == "yes" ]] ; then + build_static="yes" + search_static="yes" + elif [[ ${enable_static} == "no" ]] ; then + build_static="no" + search_static="no" + fi + + if [[ ${search_shared} == "no" ]] ; then + arguments_shared= + fi + + if [[ ${search_static} == "no" ]] ; then + arguments_static= + fi +} + +bootstrap_operation_build_validate_build() { + + if [[ ${build_compiler} == "" ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: Cannot Build, no '${c_notice}build_compiler${c_error}' specified, such as '${c_notice}gcc${c_error}'.${c_reset}" + fi + + let failure=1 + fi + + if [[ ${build_indexer} == "" ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: Cannot Build, no '${c_notice}build_indexer${c_error}' specified, such as '${c_notice}ar${c_error}'.${c_reset}" + fi + + let failure=1 + fi + + if [[ ${failure} -eq 1 ]] ; then + return 1 + fi + + return 0 +} + +bootstrap_operation_build_validate_paths() { + + if [[ ${path_sources} == "" || ! -d ${path_sources} ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: The sources directory ${c_notice}${path_sources}${c_error} is not a valid directory.${c_reset}" + fi + + let failure=1 + fi + + if [[ ${failure} -eq 0 && ${path_sources_object} != "" && ! -d ${path_sources_object} ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: The sources object directory ${c_notice}${path_sources_object}${c_error} is not a valid directory.${c_reset}" + fi + + let failure=1 + fi + + if [[ ${failure} -eq 1 ]] ; then + return 1 + fi + + return 0 +} + +bootstrap_operation_build_validate_search() { + + # When not in search exclusive mode, allow static libraries to be linked into shared libraries if the shared library is not found first. + if [[ ${search_exclusive} == "no" ]] ; then + arguments_shared="${arguments_shared} ${arguments_static}" + fi +} + +bootstrap_operation_build_validate_shared_static() { + + if [[ ${build_shared} != "yes" && ${build_static} != "yes" ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: Cannot Build, either build_shared or build_static must be set to 'yes'.${c_reset}" + fi + + let failure=1 + fi + + if [[ ${search_shared} != "yes" && ${search_static} != "yes" ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: Cannot Build, either search_shared or search_static must be set to 'yes'.${c_reset}" + fi + + let failure=1 + fi + + if [[ ${failure} -eq 1 ]] ; then + return 1 + fi + + return 0 +} + +bootstrap_operation_build_validate_sources() { + + for i in ${sources_script} ; do + if [[ ${i} != "$(sed -e 's|^//*||' -e 's|^\.\.//*||' -e 's|/*$||' <<< ${i})" ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: Cannot Build, invalid build_sources_script path provided: '${i}'.${c_reset}" + fi + + let failure=1 + fi + done + + for i in ${sources_headers} ; do + if [[ ${i} != "$(sed -e 's|^//*||' -e 's|^\.\.//*||' -e 's|/*$||' <<< ${i})" ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: Cannot Build, invalid build_sources_headers path provided: '${i}'.${c_reset}" + fi + + let failure=1 + fi + done + + for i in ${sources_library} ; do + if [[ ${i} != "$(sed -e 's|^//*||' -e 's|^\.\.//*||' -e 's|/*$||' <<< ${i})" ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: Cannot Build, invalid build_sources_library path provided: '${i}'.${c_reset}" + fi + + let failure=1 + fi + done + + for i in ${sources_library_object} ; do + if [[ ${i} != "$(sed -e 's|^//*||' -e 's|^\.\.//*||' -e 's|/*$||' <<< ${i})" ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: Cannot Build, invalid build_sources_library_object path provided: '${i}'.${c_reset}" + fi + + let failure=1 + fi + done + + for i in ${sources_program_object} ; do + if [[ ${i} != "$(sed -e 's|^//*||' -e 's|^\.\.//*||' -e 's|/*$||' <<< ${i})" ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: Cannot Build, invalid build_sources_program_object path provided: '${i}'.${c_reset}" + fi + + let failure=1 + fi + done + + for i in ${sources_program} ; do + if [[ ${i} != "$(sed -e 's|^//*||' -e 's|^\.\.//*||' -e 's|/*$||' <<< ${i})" ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: Cannot Build, invalid build_sources_program path provided: '${i}'.${c_reset}" + fi + + let failure=1 + fi + done + + for i in ${sources_documentation} ; do + if [[ ${i} != "$(sed -e 's|^//*||' -e 's|^\.\.//*||' -e 's|/*$||' <<< ${i})" ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: Cannot Build, invalid build_sources_documentation path provided: '${i}'.${c_reset}" + fi + + let failure=1 + fi + done + + for i in ${sources_setting} ; do + if [[ ${i} != "$(sed -e 's|^//*||' -e 's|^\.\.//*||' -e 's|/*$||' <<< ${i})" ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: Cannot Build, invalid build_sources_setting path provided: '${i}'.${c_reset}" + fi + + let failure=1 + fi + done + + if [[ ${failure} -eq 1 ]] ; then + return 1 + fi + + return 0 +} + +bootstrap_operation_build_prepare_versions() { + local key= + + bootstrap_id "version_file-mode" + if [[ ${variables[${key}]} != "" ]] ; then + version_file_value=${variables[${key}]} + fi + + bootstrap_id "version_target-mode" + if [[ ${variables[${key}]} != "" ]] ; then + version_target_value=${variables[${key}]} + fi + + if [[ ${version_file_value} == "" ]] ; then + version_file_value="micro" + fi + + if [[ ${version_target_value} == "" ]] ; then + version_target_value="major" + fi + + if [[ ${version_major} == "" ]] ; then + version_major_prefix= + fi + + if [[ ${version_minor} == "" ]] ; then + version_minor_prefix= + fi + + if [[ ${version_micro} == "" ]] ; then + version_micro_prefix= + fi + + if [[ ${version_nano} == "" ]] ; then + version_nano_prefix= + fi + + if [[ ${version_file_value} == "major" ]] ; then + version_file="${version_major_prefix}${version_major}" + elif [[ ${version_file_value} == "minor" ]] ; then + version_file="${version_major_prefix}${version_major}${version_minor_prefix}${version_minor}" + elif [[ ${version_file_value} == "micro" ]] ; then + version_file="${version_major_prefix}${version_major}${version_minor_prefix}${version_minor}${version_micro_prefix}${version_micro}" + elif [[ ${version_file_value} == "nano" ]] ; then + version_file="${version_major_prefix}${version_major}${version_minor_prefix}${version_minor}${version_micro_prefix}${version_micro}${version_nano_prefix}${version_nano}" + fi + + if [[ ${version_target_value} == "major" ]] ; then + version_target="${version_major_prefix}${version_major}" + elif [[ ${version_target_value} == "minor" ]] ; then + version_target="${version_major_prefix}${version_major}${version_minor_prefix}${version_minor}" + elif [[ ${version_target_value} == "micro" ]] ; then + version_target="${version_major_prefix}${version_major}${version_minor_prefix}${version_minor}${version_micro_prefix}${version_micro}" + elif [[ ${version_target_value} == "nano" ]] ; then + version_target="${version_major_prefix}${version_major}${version_minor_prefix}${version_minor}${version_micro_prefix}${version_micro}${version_nano_prefix}${version_nano}" + fi +} + +bootstrap_operation_clean() { + + local i= + + for i in ${path_build}{documents,documentation,includes,libraries,objects,programs,settings,stage} ; do + if [[ -e ${i} ]] ; then + rm ${verbose_common} -Rf ${i} + fi + done + + if [[ -f ${project_built}-${settings_name}.prepared ]] ; then + rm ${verbose_common} -f ${project_built}-${settings_name}.prepared + fi + + if [[ -f ${project_built_shared}-${settings_name}.built ]] ; then + rm ${verbose_common} -f ${project_built_shared}-${settings_name}.built + fi + + if [[ -f ${project_built_static}-${settings_name}.built ]] ; then + rm ${verbose_common} -f ${project_built_static}-${settings_name}.built + fi +} + +bootstrap_cleanup() { + + unset bootstrap_copyright + unset bootstrap_main + unset bootstrap_handle_colors + unset bootstrap_help + unset bootstrap_id + unset bootstrap_load_settings + unset bootstrap_load_settings_mode + unset bootstrap_prepare_build + unset bootstrap_operation_build + unset bootstrap_operation_build_prepare_defaults + unset bootstrap_operation_build_prepare_defines + unset bootstrap_operation_build_prepare_documentation + unset bootstrap_operation_build_prepare_flags + unset bootstrap_operation_build_prepare_headers + unset bootstrap_operation_build_prepare_libraries + unset bootstrap_operation_build_prepare_objects + unset bootstrap_operation_build_prepare_paths + unset bootstrap_operation_build_prepare_programs + unset bootstrap_operation_build_prepare_remaining + unset bootstrap_operation_build_prepare_settings + unset bootstrap_operation_build_prepare_shared_static + unset bootstrap_operation_build_prepare_versions + unset bootstrap_operation_build_validate_build + unset bootstrap_operation_build_validate_paths + unset bootstrap_operation_build_validate_search + unset bootstrap_operation_build_validate_shared_static + unset bootstrap_operation_build_validate_sources + unset bootstrap_operation_clean + unset bootstrap_cleanup +} + +bootstrap_main ${*} diff --git a/data/build/defines b/data/build/defines new file mode 100644 index 0000000..82abf48 --- /dev/null +++ b/data/build/defines @@ -0,0 +1,9 @@ +# fss-0000 + +_di_libcap_ Disable libcap support, allow for compiling and linking without libcap (-lcap). +_di_thread_support_ Disables thread support. + +_libcap_legacy_only_ Disable functionality provided by later versions of libcap (2.43 and later). + +_pthread_attr_unsupported_ Disable non-portable functionality associated with pthread_attr. +_pthread_sigqueue_unsupported_ Disable GNU specific sigqueue(). diff --git a/data/build/dependencies b/data/build/dependencies new file mode 100644 index 0000000..dd92918 --- /dev/null +++ b/data/build/dependencies @@ -0,0 +1,42 @@ +# fss-0000 + +f_type +f_status +f_memory +f_type_array +f_string +f_utf +f_abstruse +f_capability +f_color +f_compare +f_console +f_control_group +f_conversion +f_directory +f_environment +f_execute +f_file +f_fss +f_limit +f_parse +f_path +f_pipe +f_print +f_rip +f_status_string +f_signal +f_thread + +fl_control_group +fl_conversion +fl_environment +fl_execute +fl_fss +fl_print + +fll_error +fll_execute +fll_fss +fll_print +fll_program diff --git a/data/build/fakefile b/data/build/fakefile new file mode 100644 index 0000000..ef75214 --- /dev/null +++ b/data/build/fakefile @@ -0,0 +1,27 @@ +# fss-0005 iki-0002 + +settings: + fail exit + modes individual individual_thread level monolithic clang coverage fanalyzer gcc gcc_13 test thread threadless + + environment PATH LD_LIBRARY_PATH + environment LANG LC_ALL LC_COLLATE LC_CTYPE LC_FASTMSG LC_MESSAGES LC_MONETARY LC_NUMERIC LC_TIME LOCPATH NLSPATH + +main: + build + +install: + shell ./install.sh parameter:'work' parameter:'verbosity' parameter:'color' + +help: + print + print context:'title'Fakefile Options for Firewall Program.context:'reset' + + print + print The following operations are available\: + print " - context:'notable'help:context:'reset' Perform the help operation, printing this message." + print " - context:'notable'install:context:'reset' A helper operation that simply calls the ./install.sh script with default settings." + print " - context:'notable'main:context:'reset' The default compilation using the build settings mode." + + print + print The context:'notable'install[context]:'reset' operation supports the context:'notable'work[context]:'reset', context:'notable'verbosity[context]:'reset', and context:'notable'color[context]:'reset' parameters. diff --git a/data/build/settings b/data/build/settings new file mode 100644 index 0000000..32eca62 --- /dev/null +++ b/data/build/settings @@ -0,0 +1,111 @@ +# fss-0001 +# +# Modes: +# - android: Compile on an android system (using Termux; may need modification depending on the android system). +# - clang: Use CLang rather than the default, which is generally GCC. +# - coverage: Compile for building coverage. +# - debug: Enable debugging, such as compile time debug options. +# - fanalyzer: Compile using GCC's -fanalyzer compile time option. +# - gcc: Use GCC specific settings. +# - gcc_13: Use GCC version 13 or greater specific settings. +# - individual: Compile using per project (individual) libraries, does not handle thread or threadless cases. +# - individual_thread: This is required when compiling in individual mode with "thread" mode. +# - level: Compile using per level libraries. +# - monolithic: Compile using per monolithic libraries. +# - test: Compile for a test, such as unit testing. +# - thread: Compile with thread support. +# - threadless: Compile without thread support. +# + +build_name firewall + +version_major 0 +version_minor 7 +version_micro 3 +version_file micro +version_target minor + +modes android clang coverage debug fanalyzer gcc gcc_13 individual individual_thread level monolithic test thread threadless +modes_default debug gcc monolithic thread + +build_compiler gcc +build_compiler-clang clang +build_indexer ar +build_indexer_arguments rcs +build_language c + +build_libraries_shared -lc -lcap +build_libraries_shared-individual -lfll_error -lfll_execute -lfll_fss -lfll_print -lfll_program -lfl_control_group -lfl_conversion -lfl_environment -lfl_fss -lfl_print -lf_abstruse -lf_capability -lf_color -lf_compare -lf_console -lf_control_group -lf_conversion -lf_directory -lf_environment -lf_execute -lf_file -lf_fss -lf_limit -lf_memory -lf_parse -lf_path -lf_pipe -lf_print -lf_rip -lf_signal -lf_status_string -lf_string -lf_type_array -lf_utf +build_libraries_shared-individual_thread -lf_thread +build_libraries_shared-level -lfll_2 -lfll_1 -lfll_0 +build_libraries_shared-monolithic -lfll + +build_libraries_static -l:libc.a -l:libcap.a +build_libraries_static-individual -l:libfll_error.a -l:libfll_execute.a -l:libfll_fss.a -l:libfll_print.a -l:libfll_program.a -l:libfl_control_group.a -l:libfl_conversion.a -l:libfl_environment.a -l:libfl_fss.a -l:libfl_print.a -l:libf_abstruse.a -l:libf_capability.a -l:libf_color.a -l:libf_compare.a -l:libf_console.a -l:libf_control_group.a -l:libf_conversion.a -l:libf_directory.a -l:libf_environment.a -l:libf_execute.a -l:libf_file.a -l:libf_fss.a -l:libf_limit.a -l:libf_memory.a -l:libf_parse.a -l:libf_path.a -l:libf_pipe.a -l:libf_print.a -l:libf_rip.a -l:libf_signal.a -l:libf_status_string.a -l:libf_string.a -l:libf_type_array.a -l:libf_utf.a +build_libraries_static-individual_thread -l:libf_thread.a +build_libraries_static-level -l:libfll_2.a -l:libfll_1.a -l:libfll_0.a +build_libraries_static-monolithic -l:libfll.a + +build_sources_library main/common.c main/common/define.c main/common/enumeration.c main/common/string.c main/common/type.c +build_sources_library main/print/debug.c main/print/error.c main/print/message.c main/print/warning.c +build_sources_library main/operate.c main/operate/buffer.c main/operate/chains.c main/operate/create.c main/operate/default.c main/operate/delete.c main/operate/process.c main/operate/rules.c main/operate/show.c +build_sources_library main/firewall.c main/signal.c main/thread.c + +build_sources_program config.c main/main.c + +build_sources_headers main/common.h main/common/define.h main/common/enumeration.h main/common/string.h main/common/type.h +build_sources_headers main/print/debug.h main/print/error.h main/print/message.h main/print/warning.h +build_sources_headers main/operate.h main/operate/buffer.h main/operate/chains.h main/operate/create.h main/operate/default.h main/operate/delete.h main/operate/process.h main/operate/rules.h main/operate/show.h +build_sources_headers main/firewall.h main/operate.h main/signal.h main/thread.h + +build_sources_documentation man + +build_sources_setting network + +build_script yes +build_shared yes +build_static no + +path_headers program/firewall +path_library_script script +path_library_shared shared +path_library_static static +path_object_script script +path_object_shared shared +path_object_static static +path_program_script script +path_program_shared shared +path_program_static static + +has_path_standard yes +preserve_path_headers yes + +search_exclusive yes +search_shared yes +search_static yes + +environment PATH LD_LIBRARY_PATH +environment LANG LC_ALL LC_COLLATE LC_CTYPE LC_FASTMSG LC_MESSAGES LC_MONETARY LC_NUMERIC LC_TIME LOCPATH NLSPATH + +#defines -D_di_libcap_ +defines -D_libcap_legacy_only_ +defines-android -D_di_f_thread_attribute_affinity_get_ -D_di_f_thread_attribute_affinity_set_ -D_di_f_thread_attribute_concurrency_get_ -D_di_f_thread_attribute_concurrency_set_ -D_di_f_thread_attribute_default_get_ -D_di_f_thread_attribute_default_set_ -D_di_f_thread_cancel_ -D_di_f_thread_cancel_state_set_ -D_di_f_thread_cancel_test_ -D_di_f_thread_join_try_ -D_di_f_thread_join_timed_ -D_pthread_mutex_prioceiling_unsupported_ -D_di_f_thread_semaphore_file_close_ -D_di_f_thread_semaphore_file_open_ -D_di_f_thread_semaphore_file_delete_ -D_di_f_thread_cancel_type_set_ +defines-debug -D_en_f_status_debug_ +defines-thread -D_pthread_attr_unsupported_ -D_pthread_sigqueue_unsupported_ +defines-threadless -D_di_thread_support_ + +flags -O2 -g -fdiagnostics-color=always -Wno-logical-not-parentheses -Wno-parentheses -Wno-missing-braces +flags -fstack-clash-protection -fno-delete-null-pointer-checks +flags -Wl,-z,nodlopen -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now +flags-android -Wno-implicit-function-declaration -Wl,-z,norelro +flags-clang -Wno-logical-op-parentheses +flags-coverage -O0 --coverage -fprofile-abs-path -fprofile-dir=build/coverage/ +flags-fanalyzer -fanalyzer +flags-gcc_13 -fstrict-flex-arrays=3 +flags-test -O0 -fstack-protector-strong -Wall +flags-thread -pthread + +flags_library -fPIC +flags_object -fPIC +flags_program -fPIE +flags_program-android -fPIE -Wl,-z,relro diff --git a/data/documentation/man/man1/firewall.1 b/data/documentation/man/man1/firewall.1 new file mode 100644 index 0000000..5a2a111 --- /dev/null +++ b/data/documentation/man/man1/firewall.1 @@ -0,0 +1,62 @@ +.TH FIREWALL "1" "April 2025" "Kevux - Firewall 0.7.3" "User Commands" +.SH NAME +firewall \- A basic iptables based firewall manager for the Kevux distribution. +.SH SYNOPSIS +.B firewall +[\fI\,OPTIONS\/\fR] [\fI\,COMMAND\/\fR] +.SH DESCRIPTION +.PP +.SH OPTIONS +.TP +\fB\{\-h, \-\-help\fR +Print the help message. +.TP +\fB+C, ++copyright\fR +Print the copyright. +\fB+d, ++dark\fR +Output using colors that show up better on dark backgrounds. +.TP +\fB+l, ++light\fR +Output using colors that show up better on light backgrounds. +.TP +\fB+n, ++no_color\fR +Do not print using color. +.TP +\fB+Q, ++quiet\fR +Decrease verbosity, silencing most output. +.TP +\fB+E, ++error\fR +Decrease verbosity, using only error output. +.TP +\fB+N, ++normal\fR +Set verbosity to normal. +.TP +\fB+V, ++verbose\fR +Increase verbosity beyond normal output. +.TP +\fB+D, ++debug\fR +Enable debugging, significantly increasing verbosity beyond normal output. +.TP +\fB+v, ++version\fR +Print only the version number. +.SH COMMAND +.TP +\fBstart\fR +Turn on the firewall. +.TP +\fBstop\fR +Turn off the firewall. +.TP +\fBrestart\fR +Turn off and then turn on the firewall. +.TP +\fBlock\fR +Prevent all communication. +.TP +\fBshow\fR +Show active firewall settings. +.SH AUTHOR +Written by Kevin Day. +.SH COPYRIGHT +.PP +Copyright \(co 2007-2025 Kevin Day, GNU LGPL Version 2.1 or later. diff --git a/data/settings/network/firewall/default-blacklist b/data/settings/network/firewall/default-blacklist new file mode 100644 index 0000000..4f13080 --- /dev/null +++ b/data/settings/network/firewall/default-blacklist @@ -0,0 +1 @@ +# fss-0000 diff --git a/data/settings/network/firewall/default-whitelist b/data/settings/network/firewall/default-whitelist new file mode 100644 index 0000000..4f13080 --- /dev/null +++ b/data/settings/network/firewall/default-whitelist @@ -0,0 +1 @@ +# fss-0000 diff --git a/data/settings/network/firewall/example-device-firewall b/data/settings/network/firewall/example-device-firewall new file mode 100644 index 0000000..7a7143e --- /dev/null +++ b/data/settings/network/firewall/example-device-firewall @@ -0,0 +1,241 @@ +# fss-0002 +# valid tool: iptables, ip6tables, ip46tables (ip46tables = both ip4 and ip6 tables, which is the default). +# valid direction: input, output, none. +# valid device: all, this, (any device name goes here without parenthesis). +# valid action: append, insert, policy, none. +# valid procotol: none, (any valid iptables protocol type, such as tcp, udp, and icmp). +# reserved chains: INPUT, OUTPUT, FORWARD, POSTROUTING, PREROUTING, none (this only applies from within a 'main' list). +# some options for -j: ACCEPT, REJECT, DROP, RETURN, LOG, AUDIT, CHECKSUM, CLASSIFY, CLUSTERIP, CONNMARK, CONNSECMARK, CT, DNAT, DNPT, DSCP, ECN, HL, HMARK, IDLETIMER, LED, MARK, MASQUERADE, MIRROR, NETMAP, NFLOG, NFQUEUE, NOTRACK, RATETEST, REDIRECT, SAME, SECMARK, SET, SNAT, SNPT, TCPMSS,TCPOPTSTRIP, TEE, TOS, TPROXY, TRACE, TTL, ULOG. +# some options for -t: nat, mangle, filter, raw, security (filter is the default). +# some options for --state: NEW, ESTABLISHED, RELATED, INVALID, UNTRACKED, SNAT, DNAT. +# some options for --ctstatus: NONE, EXPECTED, SEEN_REPLY, ASSURED, CONFIRMED. + +main: + chain INPUT + device this + direction none + + # Define a blacklist and a whitelist, put ip addresses in the file named 'example-device-whitelist' separated by white space to whitelist an ip address + # (ip_list might be removed in the future once I figure out how ipset works and confirm if ipset can replace my ip_list.) + #ip_list source example-device-whitelist -j ACCEPT + #ip_list source example-device-blacklist -j REJECT + #ip_list destination example-device-whitelist -j ACCEPT + #ip_list destination example-device-blacklist -j REJECT + + # Connection marking for vlans or QoS (via: tc). + #chain PREROUTING + #rule -t mangle -j CONNMARK --restore-mark + #chain INPUT + + # save markings that have been restored (prerouting). + #chain PREROUTING + #rule -t mangle -m mark --mark 2 -j CONNMARK --save-mark + #rule -t mangle -m mark --mark 3 -j CONNMARK --save-mark + #chain INPUT + + # example rate limit using marking for port 22 + #protocol tcp + #chain OUTPUT + #direction output + #rule -t mangle --sport 22 -j MARK --set-mark 2 + #chain INPUT + #direction input + #rule -t mangle --dport 22 -j MARK --set-mark 2 + #direction none + + # rate limit when there are 8 or more connections from a single host. + #protocol tcp + #chain OUTPUT + #rule -t mangle -m connlimit --connlimit-above 7 -j MARK --set-mark 3 + #chain INPUT + #rule -t mangle -m connlimit --connlimit-above 7 -j MARK --set-mark 3 + + # save markings that have been assigned (postrouting). + #protocol none + #chain POSTROUTING + #rule -t mangle -m mark --mark 2 -j CONNMARK --save-mark + #rule -t mangle -m mark --mark 3 -j CONNMARK --save-mark + #chain INPUT + + + # randomly trigger the rule (51% of the time) and then the reset of the time go to the second rule. + # this can be very useful in distributing connections between different devices or servers. + #rule -m random --average 51 -j example_rule_1 + #rule -j example_rule_2 + + +input-tcp: + device this + direction input + protocol tcp + + ## Http / Web + #rule --dport 80 -j LOG --log-prefix "TRAFFIC:WEB " + #rule --dport 80 -j ACCEPT + + ## Http / Web redirect to Https / Secure Web + #tool iptables + #rule -t nat --dport 80 -j REDIRECT --to-port 443 + #tool ip46tables + #direction input + + ## Https / Secure Web + #rule --dport 443 -j LOG --log-prefix "TRAFFIC:WEB " + #rule --dport 443 -j ACCEPT + + ## Http / Https / Web throttle connections that occur too often. + #rule --dport 80 --sync -m recent --name http_throttle --set + #rule --dport 80 --sync -m recent --name http_throttle --update --seconds 3 --hitcount 10 -j DROP + #rule --dport 443 --sync -m recent --name http_throttle --set + #rule --dport 443 --sync -m recent --name http_throttle --update --seconds 3 --hitcount 10 -j DROP + + ## MySQL + #rule --dport 3306 -j ACCEPT + + ## Music Player Daemon + #rule --dport 6600 -j ACCEPT + + ## Camsource + #rule --dport 9192 -j ACCEPT + + ## Cups Printer Administration + #rule --dport 631 -j ACCEPT + + ## Ssh (OpenSSH) + #rule --dport 22 -j LOG --log-prefix "TRAFFIC:SSH " + #rule --dport 22 -j ACCEPT + + ## clamd (Clam Antivirus) - remote access, not needed for normal + #rule --dport 3310 -j ACCEPT + + ## Virtual Network Client Server (add 1 for each seperat vnc server) + #rule --dport 5900 -j ACCEPT + + ## Printer Port, is probably open...safer to close unless you are SERVING a printer + #rule --dport 515 -j REJECT + + ## Subversion server + #rule --dport 3690 -j ACCEPT + + ## Silc server + #rule --dport 706 -j ACCEPT + + ## Worms of Prey + #rule --dport 47288 -j ACCEPT + + ## Git Daemon + #rule --dport 9418 -j ACCEPT + + ## Ldap Server + #rule --dport 389 -j ACCEPT + #rule --dport 636 -j ACCEPT + #rule --dport 1636 -j ACCEPT + + ## Mail Server (25 = SMTP, 465 = SMTPS, 993 = IMAP, 995 = POP) + #rule --dport 25 -j ACCEPT + + +input-udp: + device this + direction input + protocol udp + + ## DNS Server (Bind or Maradns) (zoneserver from maradns does this portion) + #rule --dport 53 -j ACCEPT + + ## DHCP Server (providing dhcp address to clients) + #tool iptables + #rule --sport 68 -d 255.255.255.255 --dport 67 -j ACCEPT + #tool ip46tables + + ## Subversion server + #rule --dport 3690 -j ACCEPT + + ## Worms of Prey + #rule --sport 47288:47544 -j ACCEPT + #rule --dport 47288:47544 -j ACCEPT + + +input-icmp: + device this + direction input + protocol icmp + + # allow all icmp input, such as pings + #rule -j ACCEPT + + # allow icmp: echo reply (outbound ping) + ##rule --icmp-type 0 -j ACCEPT + + # allow icmp: destination unreachable + #rule --icmp-type 3 -j ACCEPT + + # allow icmp: source quench + #rule --icmp-type 4 -j ACCEPT + + # allow icmp: redirect + #rule --icmp-type 5 -j ACCEPT + + # allow icmp: echo request (inbound ping) + #rule --icmp-type 8 -j ACCEPT + + # allow icmp: router advertisement + #rule --icmp-type 9 -j ACCEPT + + # allow icmp: router Solicitation + #rule --icmp-type 10 -j ACCEPT + + # allow icmp: time exceeded + #rule --icmp-type 11 -j ACCEPT + + # allow icmp: bad ip header + #rule --icmp-type 12 -j ACCEPT + + # allow icmp: timestamp + #rule --icmp-type 13 -j ACCEPT + + # allow icmp: timestamp reply + #rule --icmp-type 14 -j ACCEPT + + # allow icmp: information request + #rule --icmp-type 15 -j ACCEPT + + # allow icmp: information reply + #rule --icmp-type 16 -j ACCEPT + + # allow icmp: address request + #rule --icmp-type 17 -j ACCEPT + + # allow icmp: address reply + #rule --icmp-type 18 -j ACCEPT + + # allow icmp: traceroute + #rule --icmp-type 30 -j ACCEPT + + +output-tcp: + device this + direction output + protocol tcp + + +output-udp: + device this + direction output + protocol udp + + ## DNS Server (Bind or Maradns) (zoneserver from maradns does this portion) + #rule --dport 53 -j ACCEPT + + ## DHCP Server (providing dhcp address to clients) + #tool iptables + #rule --sport 67 -d 255.255.255.255 --dport 68 -j ACCEPT + #tool ip46tables + + +output-icmp: + device this + direction output + protocol icmp + + diff --git a/data/settings/network/firewall/firewall-first b/data/settings/network/firewall/firewall-first new file mode 100644 index 0000000..386b26b --- /dev/null +++ b/data/settings/network/firewall/firewall-first @@ -0,0 +1,667 @@ +# fss-0002 + +main: + # initialize the firewall + action none + direction none + protocol none + chain none + + rule -F + rule -Z + + tool iptables + rule -t nat -F + rule -t mangle -F + tool ip46tables + + +INPUT: + # main input chain, expect this to act as the final RETURN handler. + direction input + protocol none + + # handle local (loopback) connections. + device lo + rule -j input-loop + device all + + # Drop all INVALID packets so they aren't even processed + rule -m conntrack --ctstate INVALID -j input-invalid + + # Allow ALL connections that have already been established by this host + #rule -m state --state ESTABLISHED,RELATED -j ACCEPT + rule -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT + + # send to whitelist and blacklist, which should return here. + rule -j input-blacklist + rule -j input-whitelist + + # Drop multicasts and broadcasts, they should not exist for a router and in most cases should be avoided. + # unicasts are the normal behavior and blocking them would be very unusual. + rule -m pkttype --pkt-type broadcast -j input-casting + rule -m pkttype --pkt-type multicast -j input-casting + #rule -m pkttype --pkt-type unicast -j input-casting + + # send all tcp packets to the tcp queue + protocol tcp + rule -m state --state NEW -j input-tcp + + # send all udp packets to the udp queue + protocol udp + rule -m state --state NEW -j input-udp + + # send all icmp packets to the icmp queue + protocol icmp + rule -m state --state NEW -j input-icmp + + # send all icmpv6 packets to the icmpv6 queue + tool ip6tables + protocol icmpv6 + rule -m state --state NEW -j input-icmpv6 + tool ip46tables + + # load custom device-specific rules + rule -j input-devices + + # remaining packets + #rule -j LOG --log-prefix "INPUT:" + rule -j DROP + + +input-invalid: + direction input + protocol none + + # silently drop invalid RST tcp packets instead of sending a RST back. + protocol tcp + rule --tcp-flags RST RST -j DROP + + # invalid FIN,ACK (server is wanting a FIN response), silently DROP it, send RST back, or send a FIN back. + #rule --tcp-flags ALL ACK,FIN -j DROP + #rule --tcp-flags ALL ACK,FIN -j REJECT --reject-with tcp-reset + rule --tcp-flags ALL ACK,FIN -j ACCEPT + + + # remaining packets + protocol none + #rule -j LOG --log-prefix "INV_IN:" + rule -j DROP + + +input-invalid-stream: + direction input + protocol tcp + + # remaining packets + rule -j REJECT --reject-with tcp-reset + + +input-loop: + direction input + protocol none + + # allow cups via loopback. + protocol tcp + tool iptables + rule --sport 631 -s 127.0.0.0/8 -d 127.0.0.0/8 -j ACCEPT + rule --dport 631 -s 127.0.0.0/8 -d 127.0.0.0/8 -j ACCEPT + + # allow local dns server + #protocol udp + #rule --dport 53 -s 127.0.0.0/8 -d 127.0.1.1 -j ACCEPT + + # this is the localhost address, valid localhost are allowed to return to the previous chain. + protocol none + rule -s 127.0.0.0/8 -d 127.0.0.0/8 -j RETURN + tool ip6tables + rule -s ::1 -d ::1 -j RETURN + tool iptables + + # it may be necessay to add a return for individual ips because there are some cases that result in non-localhost addresses going through loopback. + #rule -s 192.168.0.1 -d 192.168.0.1 -j RETURN + tool ip46tables + + # remaining packets + #rule -j DROP + rule -j RETURN + + +input-blacklist: + direction input + protocol none + + +input-whitelist: + direction input + protocol none + + +input-devices: + direction input + protocol none + + # add device-specific rules here. + + +input-tcp: + direction input + protocol tcp + + # Resist TCP sequence number spoof attacks. + rule --tcp-flags SYN,ACK SYN,ACK -m conntrack --ctstate NEW -j input-invalid + + # TCP streams must always start with SYN, all others are invalid and may be an attack. + rule ! --syn -m conntrack --ctstate NEW -j input-invalid-stream + + # Prevent an XMAS attacks + rule --tcp-flags ALL FIN,URG,PSH -j input-invalid + rule --tcp-flags ALL ALL -j input-invalid + rule --tcp-flags ALL SYN,RST,ACK,FIN,URG -j input-invalid + + # Prevent NULL attack + rule --tcp-flags ALL NONE -j input-invalid + + # Prevent Sync Reset Attacks + rule --tcp-flags SYN,RST SYN,RST -j input-invalid + rule --tcp-flags SYN,FIN SYN,FIN -j input-invalid + + # XMPP ports. + #rule -m multiport --dports 5222,5223,5269 -j ACCEPT + + # Postgresql standard port + #rule --dport 5432 -j ACCEPT + + # Mysql standard port + #rule --dport 5432 -j ACCEPT + + # Oracle standard port + #rule --dport 1521 -j ACCEPT + + # Web standard ports + #rule -m multiport --dports 80,443,8080,8181,8443,8099,9000,9001,9002 -j ACCEPT + + # ldap standard ports + #rule -m multiport --dports 389,636,1636 -j ACCEPT + + # mail standard ports + #rule -m multiport --dports 25,465,993 -j ACCEPT + + # ssh standard port + #rule --dport 22 -j ACCEPT + + # require 3 knocks before opening the door for SSH. + #rule --dport 22 -m state --state NEW -m recent --set + #rule --dport 22 -m state --state NEW -m recent --update --seconds 15 --hitcount 3 -j ACCEPT + + # common chef ssh ports + #rule --dport 2200:2210 -j ACCEPT + + # gpg standard port + #rule --dport 9050 -j ACCEPT + + # ftp standard port + #rule --dport 21 -j ACCEPT + + # dns standard port (via tcp) + #rule --dport 53 -j ACCEPT + + # rdp standard port + #rule --dport 3389 -j ACCEPT + + # spice standard ports + #rule -m multiport --dports 5900:5905 -j ACCEPT + + # allow high ports + #rule -m multiport --dports 49152:65535 -j ACCEPT + + # accept all loopback + tool iptables + rule -d 127.0.0.0/8 -j ACCEPT + tool ip6tables + rule -d ::1 -j ACCEPT + tool ip46tables + + +input-udp: + direction input + protocol udp + + # openvpn standard port + #rule --dport 1194 -j ACCEPT + + # dns standard port + #rule --dport 53 -j ACCEPT + + # mdns standard port + #rule --dport 5353 -j ACCEPT + + # dhcp standard port + rule --sport 67:68 --dport 67:68 -j ACCEPT + + # ntp standard port + #rule --dport 123 -j ACCEPT + + # teeworlds game server and client + #rule --dport 8300:8310 -j ACCEPT + + # XMPP ports. + #rule -m multiport --dports 5222,5223,5269 -j ACCEPT + + # allow high ports + #rule -m multiport --dports 49152:65535 -j ACCEPT + + # accept all loopback + tool iptables + rule -d 127.0.0.0/8 -j ACCEPT + tool ip6tables + rule -d ::1 -j ACCEPT + tool ip46tables + + +input-icmp: + direction input + protocol icmp + tool iptables + + # destination unreachable + rule --icmp-type 3 -j ACCEPT + + # redirect + rule --icmp-type 5 -j ACCEPT + + # (outgoing) ping + rule --icmp-type 0 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT + + # time exceeded + rule --icmp-type 11 -j ACCEPT + + # parameter problem + rule --icmp-type 12 -j ACCEPT + + # all loopback ICMP traffic + tool iptables + rule -i lo -s 127.0.0.0/8 -d 127.0.0.0/8 -j ACCEPT + tool ip46tables + + # remaining packets + #rule -j LOG --log-prefix "ICMP_IN:" + #rule -j DROP + rule -j ACCEPT + + +input-icmpv6: + direction input + protocol icmp + tool ip6tables + + #rule -j LOG --log-prefix "ICMP6_IN:" + #rule -j DROP + rule -j ACCEPT + + tool ip46tables + + +input-casting: + direction input + protocol none + tool ip46tables + + # do not auto-drop dhcp messages sent from a dhcp server to a local dhcp client. + # dhcp offer/acknowledge (the source address must be the routers address, so do not allow 0.0.0.0/0) + protocol udp + tool iptables + rule --sport 67 -d 255.255.255.255 --dport 68 -j RETURN + protocol none + + # Move ICMPv6 along. + tool ip6tables + protocol icmpv6 + rule -m state --state NEW -j input-icmpv6 + tool ip46tables + + # drop all remaining broadcasts and multicasts + #rule -j LOG --log-prefix "CAST_IN:" + #rule -j DROP + rule -j RETURN + + +OUTPUT: + # main output chain, expect this to act as the final RETURN handler. + direction output + protocol none + + # handle local (loopback) connections. + device lo + rule -j output-loop + device all + + # Drop all INVALID packets so they aren't even processed + rule -m conntrack --ctstate INVALID -j output-invalid + + # Allow ALL connections that have already been established by this host + #rule -m state --state ESTABLISHED,RELATED -j ACCEPT + rule -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT + + # send to whitelist and blacklist, which should return here. + rule -j input-blacklist + rule -j input-whitelist + + # Drop multicasts and broadcasts, they should not exist for a router and in most cases should be avoided. + # unicasts are the normal behavior and blocking them would be very unusual. + rule -m pkttype --pkt-type broadcast -j output-casting + rule -m pkttype --pkt-type multicast -j output-casting + #rule -m pkttype --pkt-type unicast -j output-casting + + # send all tcp packets to the tcp queue + protocol tcp + rule -m state --state NEW -j output-tcp + + # send all udp packets to the udp queue + protocol udp + rule -m state --state NEW -j output-udp + + # send all icmp packets to the icmp queue + protocol icmp + rule -m state --state NEW -j output-icmp + + # send all icmpv6 packets to the icmpv6 queue + tool ip6tables + protocol icmpv6 + rule -m state --state NEW -j output-icmpv6 + tool ip46tables + + # load custom device-specific rules + rule -j input-devices + + # remaining packets + #rule -j LOG --log-prefix "OUTPUT:" + #rule -j DROP + rule -j ACCEPT + + +output-invalid: + direction output + protocol none + + # remaining packets + #rule -j LOG --log-prefix "INV_OUT:" + rule -j DROP + + +output-invalid-stream: + direction input + protocol tcp + + # remaining packets + rule -j REJECT --reject-with tcp-reset + + +output-loop: + direction output + protocol none + + # allow cups via loopback. + protocol tcp + tool iptables + rule --sport 631 -s 127.0.0.0/8 -d 127.0.0.0/8 -j ACCEPT + rule --dport 631 -s 127.0.0.0/8 -d 127.0.0.0/8 -j ACCEPT + + # allow local dns server + protocol udp + rule --sport 53 -s 127.0.0.0/8 -d 127.0.0.0/8 -j ACCEPT + + # this is the localhost address, valid localhost are allowed to return to the previous chain. + protocol none + rule -s 127.0.0.0/8 -d 127.0.0.0/8 -j RETURN + + # it may be necessay to add a return for individual ips because there are some cases that result in non-localhost addresses going through loopback. + #rule -s 192.168.0.1 -d 192.168.0.1 -j RETURN + tool ip46tables + + # remaining packets + #rule -j DROP + rule -j RETURN + + +output-blacklist: + direction output + protocol none + + +output-whitelist: + direction output + protocol none + + +output-devices: + direction output + protocol none + + # add device-specific rules here. + + +output-tcp: + direction output + protocol tcp + + # allow sending TCP RST even when there is no valid local connection + protocol tcp + rule --tcp-flags RST RST -j ACCEPT + + # allow sending ACK,PSH,FIN even when there is no valid local connection. + # the connection may already be closed locally by the time this packet goes out and it could improperly be marked as invalid before it leaves the system. + # allowing this ensures that the client gets the final disconnect acknowledgment. + rule --tcp-flags ALL ACK,FIN -j ACCEPT + rule --tcp-flags ALL ACK,PSH,FIN -j ACCEPT + + # Resist TCP sequence number spoof attacks. + rule --tcp-flags SYN,ACK SYN,ACK -m conntrack --ctstate NEW -j input-invalid + + # TCP streams must always start with SYN, all others are invalid and may be an attack. + rule ! --syn -m conntrack --ctstate NEW -j output-invalid-stream + + # Prevent an XMAS attacks + rule --tcp-flags ALL FIN,URG,PSH -j output-invalid + rule --tcp-flags ALL ALL -j output-invalid + rule --tcp-flags ALL SYN,RST,ACK,FIN,URG -j output-invalid + + # Prevent NULL attack + rule --tcp-flags ALL NONE -j output-invalid + + # Prevent Sync Reset Attacks + rule --tcp-flags SYN,RST SYN,RST -j output-invalid + rule --tcp-flags SYN,FIN SYN,FIN -j output-invalid + + # Postgresql standard port + #rule --sport 5432 -j ACCEPT + + # Mysql standard port + #rule --sport 5432 -j ACCEPT + + # Oracle standard port + #rule --sport 1521 -j ACCEPT + + # Web standard ports + rule -m multiport --dports 80,443,8080,8181,8443,8099,9000,9001,9002 -j ACCEPT + #rule -m multiport --sports 80,443,8080,8181,8443,8099,9000,9001,9002 -j ACCEPT + + # ldap standard ports + rule -m multiport --dports 389,636,1636 -j ACCEPT + #rule -m multiport --sports 389,636,1636 -j ACCEPT + + # mail standard ports + rule -m multiport --dports 25,465,993 -j ACCEPT + #rule -m multiport --sports 25,465,993 -j ACCEPT + + # XMPP ports + rule -m multiport --dports 5222,5223,5269 -j ACCEPT + + # ssh standard port + rule --dport 22 -j ACCEPT + #rule --sport 22 -j ACCEPT + + # common chef ssh ports + #rule --dport 2200:2210 -j ACCEPT + #rule --sport 2200:2210 -j ACCEPT + + # gpg standard port + rule --dport 9050 -j ACCEPT + #rule --sport 9050 -j ACCEPT + + # pgp keyserver port + rule --dport 11371 -j ACCEPT + + # ftp standard port + rule --dport 21 -j ACCEPT + #rule --sport 21 -j ACCEPT + + # dns standard port (via tcp) + rule --dport 53 -j ACCEPT + #rule --sport 53 -j ACCEPT + + # rdp standard port + rule --dport 3389 -j ACCEPT + #rule --sport 3389 -j ACCEPT + + # spice standard ports + rule -m multiport --dports 5900:5905 -j ACCEPT + #rule -m multiport --sports 5900:5905 -j ACCEPT + + # allow high ports + rule -m multiport --sports 49152:65535 -j ACCEPT + #rule -m multiport --dports 49152:65535 -j ACCEPT + + # accept all loopback + tool iptables + rule -s 127.0.0.0/8 -j ACCEPT + tool ip6tables + rule -d ::1 -j ACCEPT + tool ip46tables + + +output-udp: + direction output + protocol udp + + # openvpn standard port + rule --dport 1194 -j ACCEPT + #rule --sport 1194 -j ACCEPT + + # dns standard port + rule --dport 53 -j ACCEPT + #rule --sport 53 -j ACCEPT + + # mdns standard port + #rule --dport 5353 -j ACCEPT + #rule --sport 5353 -j ACCEPT + + # dhcp standard port + rule --sport 67:68 --dport 67:68 -j ACCEPT + + # ntp standard port + rule --dport 123 -j ACCEPT + #rule --sport 123 -j ACCEPT + + # ntpsec standard port + rule --dport 4460 -j ACCEPT + + # teeworlds game server and client + rule --dport 8300:8310 -j ACCEPT + + # XMPP ports + rule -m multiport --dports 5222,5223,5269 -j ACCEPT + + # allow high ports + rule -m multiport --sports 49152:65535 -j ACCEPT + #rule -m multiport --dports 49152:65535 -j ACCEPT + + # accept all loopback + tool iptables + rule -s 127.0.0.0/8 -j ACCEPT + tool ip6tables + rule -d ::1 -j ACCEPT + tool ip46tables + + +output-icmp: + direction output + protocol icmp + tool iptables + + # destination unreachable + rule --icmp-type 3 -j ACCEPT + + # redirect + rule --icmp-type 5 -j ACCEPT + + # (outgoing) ping + rule --icmp-type 8 -m conntrack --ctstate NEW,ESTABLISHED,RELATED -j ACCEPT + + # time exceeded + rule --icmp-type 11 -j ACCEPT + + # parameter problem + rule --icmp-type 12 -j ACCEPT + + # all loopback ICMP traffic + tool iptables + rule -o lo -s 127.0.0.0/8 -d 127.0.0.0/8 -j ACCEPT + tool ip46tables + + # remaining packets + #rule -j LOG --log-prefix "ICMP_OUT:" + #rule -j DROP + rule -j ACCEPT + + +output-icmpv6: + direction output + protocol icmp + tool ip6tables + + #rule -j LOG --log-prefix "ICMP6_OUT:" + #rule -j DROP + rule -j ACCEPT + + tool ip46tables + + +output-casting: + direction output + protocol none + tool ip46tables + + # do not auto-drop dhcp client messages sent to a dhcp server. + # dhcp discover/request (for the request, the dhcp server ip address is known but for some reason the dhcp standard states tat the src is 0.0.0.0. + protocol udp + tool iptables + rule --sport 68 -d 255.255.255.255 --dport 67 -j RETURN + protocol none + tool ip46tables + + # Move ICMPv6 along. + tool ip6tables + protocol icmpv6 + rule -m state --state NEW -j output-icmpv6 + tool ip46tables + + # drop all remaining broadcasts and multicasts + #rule -j LOG --log-prefix "CAST:" + #rule -j DROP + rule -j ACCEPT + + +FORWARD: + + # load custom device-specific rules + rule -j forward-devices + + #rule -j LOG --log-prefix "FORWARDs:" + #rule -j DROP + rule -j ACCEPT + + +forward-devices: + + # add device-specific rules here. diff --git a/data/settings/network/firewall/firewall-last b/data/settings/network/firewall/firewall-last new file mode 100644 index 0000000..1f8375b --- /dev/null +++ b/data/settings/network/firewall/firewall-last @@ -0,0 +1,2 @@ +# fss-0002 + diff --git a/data/settings/network/firewall/firewall-other b/data/settings/network/firewall/firewall-other new file mode 100644 index 0000000..5112a34 --- /dev/null +++ b/data/settings/network/firewall/firewall-other @@ -0,0 +1,69 @@ +# fss-0002 + +stop: + action policy + + chain INPUT + rule ACCEPT + + chain OUTPUT + rule ACCEPT + + chain FORWARD + rule ACCEPT + + chain none + direction none + action none + rule -t filter --flush + + tool iptables + rule -t nat --flush + rule -t mangle --flush + tool ip46tables + + rule --delete-chain + + tool iptables + rule -t nat --delete-chain + rule -t mangle --delete-chain + tool ip46tables + + +lock: + action policy + + chain INPUT + rule DROP + + chain OUTPUT + rule DROP + + chain FORWARD + rule DROP + + chain none + direction none + action none + rule --flush + + tool iptables + rule -t nat --flush + rule -t mangle --flush + tool ip46tables + + rule --delete-chain + + tool iptables + rule -t nat --delete-chain + rule -t mangle --delete-chain + tool ip46tables + + device lo + action insert + direction output + chain OUTPUT + rule -j ACCEPT + direction input + chain INPUT + rule -j ACCEPT diff --git a/documents/readme.bootstrap.txt b/documents/readme.bootstrap.txt new file mode 100644 index 0000000..505b40c --- /dev/null +++ b/documents/readme.bootstrap.txt @@ -0,0 +1,139 @@ +# fss-0002 iki-0000 +# +# license: cc-by-sa-4.0 +# version 2024/07/10 +# +# This file (assumed to be named readme.bootstrap.txt) can be more easily read using the following iki_read commands: +# iki_read readme.bootstrap.txt +Q -w -rr FLL FLL FSS FSS -WW character "'" "'" code '"' '"' +# +# To read the "Bootstrap Readme Documentation" section of this file, use this command sequence: +# fss_basic_list_read readme.bootstrap.txt +Q -cn "Bootstrap Readme Documentation" | iki_read +Q -w -rr FLL FLL FSS FSS -WW character "'" "'" code '"' '"' +# + +Bootstrap Readme Documentation: + The FLL:"Featureless Linux Library" provides a special bootstrap script in case the bold:"Featureless Make" is not currently installed. + + The bold:"GNU Bash" scripts, called file:"bootstrap.sh" and file:"install.sh", are provided to perform this bootstrap process. + + The syntax for file:"bootstrap.sh" is\: + code:"bootstrap.sh [options]" + - where operation is one of the following: code:"build" or code:"clean". + - No code:"install" command is provided, all of the files to install may be found in the file:"build/" directory after the build command is executed. + - To install, either copy the files in the build directory to their appropriate destination or use the file:"install.sh" bold:"GNU Bash" script. + - For all operations and options, get help from the bootstrap script by appending the code:"--help" to the script, such as: code:"./bootstrap.sh --help". + - The monolithic build process is the simplest, which can be generated like the following: code:"./bootstrap.sh build -m monolithic". + - When during development, consider using a work directory, such as: code:"./bootstrap.sh --work /tmp/work". + + The syntax for file:"install.sh" is\: + code:"install.sh [options]" + - This defaults to code:"/usr/local/" paths commonly found in bold:"GNU Linux" systems. + - Accepts options for specifying specific install directory paths, such as a custom bin directory: code:"./install.sh --bindir /custom/program". + - This is a simple installer and is not intended to be an all-solution. + - For more powerful installation: manually install, use custom scripts, or use an appropriate build/install system. + - When during development, consider using a work directory, such as: code:"./install.sh --work /tmp/work". + - The code:"--work" parameter in file:"install.sh" is similar to the code:"--prefix" parameter, except that it is used for easier development scripting and also for communicating intent and has a different directory structure. + - The bold:"Featureless Make" is a build system only and not an install system, the file:"install.sh" script may still be needed to install when using the bold:"Featureless Make". + + Build Example\: + code:"./bootstrap.sh build" + + Install Example\: + code:"./install.sh" + + Manual Install Example\: + code:"cp -vR build/documentation/* /usr/share/" + code:"cp -vR build/includes/* /usr/include/" + code:"cp -vR build/libaries/shared/* /usr/lib/" + code:"cp -vR build/programs/shared/* /usr/bin/" + code:"cp -vR build/settings/* /etc/" + + If one of the build sub-directories, such as includes, libraries, programs, and settings, is empty or missing after a successful build, then there are no files of that type to install. + + Build Tree Structure Example (using the FLL:"Featureless Linux Library" code:"status_code-0.7.3" project)\: + block:" + build/ + ├── documents + ├── includes + │   └── program + │   └── status_code + │   ├── fss + │   │   ├── common.h + │   │   └── status_code.h + │   └── main + │   ├── common.h + │   ├── common-print.h + │   ├── print.h + │   └── status_code.h + ├── libraries + │   ├── script + │   ├── shared + │   │   ├── libstatus_code.so -> libstatus_code.so.0 + │   │   ├── libstatus_code.so.0 -> libstatus_code.so.0.7 + │   │   ├── libstatus_code.so.0.7 -> libstatus_code.so.0.7.3 + │   │   └── libstatus_code.so.0.7.3 + │   └── static + │   └── libstatus_code.a + ├── objects + │   ├── config.o + │   ├── fss + │   │   ├── common.o + │   │   └── status_code.o + │   ├── main + │   │   ├── common.o + │   │   ├── common-print.o + │   │   ├── print.o + │   │   ├── private-status_code.o + │   │   └── status_code.o + │   ├── script + │   ├── shared + │   └── static + ├── programs + │   ├── script + │   ├── shared + │   │   ├── fss_status_code + │   │   └── status_code + │   └── static + │   ├── fss_status_code + │   └── status_code + ├── settings + └── stage + ├── library_shared-settings.built + ├── library_static-settings.built + ├── objects_static-settings.built + ├── program_shared-settings.fss.built + ├── program_shared-settings.main.built + ├── skeleton-settings.built + ├── skeleton-settings.fss.built + ├── skeleton-settings.main.built + ├── sources_headers-settings.built + ├── sources_script-settings.built + ├── sources_script-settings.fss.built + ├── sources_script-settings.main.built + ├── sources_settings-settings.built + ├── sources_settings-settings.fss.built + └── sources_settings-settings.main.built + " + + Work Tree Sructure Example at file:"/tmp/work" (using the FLL:"Featureless Linux Library" code:"status_code-0.7.3" project)\: + block:" + /tmp/work/ + ├── includes + │   └── program + │   └── status_code + │   ├── fss + │   │   ├── common.h + │   │   └── status_code.h + │   └── main + │   ├── common.h + │   ├── common-print.h + │   ├── print.h + │   └── status_code.h + └── libraries + ├── shared + │   ├── libstatus_code.so -> libstatus_code.so.0 + │   ├── libstatus_code.so.0 -> libstatus_code.so.0.7 + │   ├── libstatus_code.so.0.7 -> libstatus_code.so.0.7.3 + │   └── libstatus_code.so.0.7.3 + └── static + └── libstatus_code.a + " diff --git a/documents/readme.build.txt b/documents/readme.build.txt new file mode 100644 index 0000000..8008060 --- /dev/null +++ b/documents/readme.build.txt @@ -0,0 +1,120 @@ +# fss-0002 iki-0000 +# +# license: cc-by-sa-4.0 +# version 2024/07/10 +# +# This file (assumed to be named readme.build.txt) can be more easily read using the following iki_read commands: +# iki_read readme.build.txt +Q -w -rr FLL FLL FSS FSS -WW character "'" "'" code '"' '"' +# +# To read the "Build Readme Documentation" section of this file, use this command sequence: +# fss_basic_list_read readme.build.txt +Q -cn "Build Readme Documentation" | iki_read +Q -w -rr FLL FLL FSS FSS -WW character "'" "'" code '"' '"' +# + +Build Readme Documentation: + The bold:"Featureless Make", or code:"fake", is a build system opposing the bold:"GNU Make" build (and install) system. + + The bold:"GNU Make" system is powerful, but introduces too much unecessary functionality. + In opposition to parts of how bold:"GNU Make" works but also in honor of the success of the bold:"GNU Make" system, the bold:"Featureless Make" system follows the following concepts\: + - A build system is just that, a build system. Do not attempt to install, leave that to the distributor or individual installer. + - A build system should not be trying to guess what is or is not on the system, instead, allow the distributor or individual installer to just specify what they want. + - Provide a simple configuration design by using the bold:"Featureless Settings Specification". + - Provide advanced functionality to provide flexibility with different system designs. + - Userspace execution calling is expensive, attempt to avoid such overhead by providing built-in functionality where reasonably possible. + - There should never need to be a code:"configure" script, like bold:"GNU Autoconf". + + The code:"fake" is designed to specifically build the FLL:"Featureless Linux Library" and encourages the use of code:"fake" to build FLL:"Featureless Linux Library". + + The code:"fake" provides two main build operations\: + - code:"build": a lean purely FSS:"Featureless Settings Specification" based build process, designed around specific but simple project designs (explicitly used by FLL:"Featureless Linux Library"). + - code:"make": a more powerful build process design to be more akin to bold:"GNU Make". + + The code:"fake" supports custom development environments using the file:"work" directory concept, such as code:"fake build -w /tmp/work". + The file:"work" directory structure is identical to the build directory structure. + + Build Example, Using code:"build"\: + code:"fake build" + + Build Example, Using code:"make"\: + code:"fake" + + Build Example, Explicitly Using code:"make"\: + code:"fake make" + + Install Example\: + code:"./install.sh" + + Manual Install Example\: + code:"cp -vR build/documentation/* /usr/share/" + code:"cp -vR build/includes/* /usr/include/" + code:"cp -vR build/libaries/shared/* /usr/lib/" + code:"cp -vR build/programs/shared/* /usr/bin/" + code:"cp -vR build/settings/* /etc/" + + Build Tree Structure Example (using the FLL:"Featureless Linux Library" code:"status_code-0.7.3" project)\: + block:" + build/ + ├── documents + ├── includes + │   └── program + │   └── status_code + │   ├── fss + │   │   ├── common.h + │   │   └── status_code.h + │   └── main + │   ├── common.h + │   ├── common-print.h + │   ├── print.h + │   └── status_code.h + ├── libraries + │   ├── script + │   ├── shared + │   │   ├── libstatus_code.so -> libstatus_code.so.0 + │   │   ├── libstatus_code.so.0 -> libstatus_code.so.0.7 + │   │   ├── libstatus_code.so.0.7 -> libstatus_code.so.0.7.3 + │   │   └── libstatus_code.so.0.7.3 + │   └── static + │   └── libstatus_code.a + ├── objects + │   ├── config.o + │   ├── fss + │   │   ├── common.o + │   │   └── status_code.o + │   ├── main + │   │   ├── common.o + │   │   ├── common-print.o + │   │   ├── print.o + │   │   ├── private-status_code.o + │   │   └── status_code.o + │   ├── script + │   ├── shared + │   └── static + ├── programs + │   ├── script + │   ├── shared + │   │   ├── fss_status_code + │   │   └── status_code + │   └── static + │   ├── fss_status_code + │   └── status_code + ├── settings + └── stage + ├── library_shared-settings.built + ├── library_static-settings.built + ├── objects_static-settings.built + ├── program_shared-settings.fss.built + ├── program_shared-settings.main.built + ├── skeleton-settings.built + ├── skeleton-settings.fss.built + ├── skeleton-settings.main.built + ├── sources_headers-settings.built + ├── sources_script-settings.built + ├── sources_script-settings.fss.built + ├── sources_script-settings.main.built + ├── sources_settings-settings.built + ├── sources_settings-settings.fss.built + └── sources_settings-settings.main.built + " + + See: FLL:"Featureless Linux Library" code:"fake" project documents and specifications for further details on how to use the bold:"Featureless Make" system. + See: FLL:"Featureless Linux Library" project documentation and specifications for how to configure the bold:"Featureless Make" FSS:"Featureless Settings Specification" files. + See: file:"readme.bootstrap.txt" for notes on building and installing when bootstrapping the library. diff --git a/documents/readme.txt b/documents/readme.txt new file mode 100644 index 0000000..8d05bf2 --- /dev/null +++ b/documents/readme.txt @@ -0,0 +1,60 @@ +# fss-0002 iki-0000 +# +# license: cc-by-sa-4.0 +# version 2024/07/10 +# +# This file (assumed to be named readme.build.txt) can be more easily read using the following iki_read commands: +# iki_read readme.txt +Q -w -rrrr API API FLL FLL FSS FSS KISS KISS -WW character "'" "'" code '"' '"' +# +# To read the "Readme Documentation" section of this file, use this command sequence: +# fss_basic_list_read readme.txt +Q -cn "Readme Documentation" | iki_read +Q -w -rrrr API API FLL FLL FSS FSS KISS KISS -WW character "'" "'" code '"' '"' +# + +Readme Documentation: + The FLL:"Featureless Linux Library" is a set of projects designed to be used for bold:"Linux" programming. + + The FLL:"Featureless Linux Library" is design around the following concepts\: + - API:"Application Programming Interface" designed around communicating to the programmer and maintaining unchanging consistency. + - Hacker friendly, promote changing the project via its designed methodologies, implementations, standards, practices, and licenses. + - Add freedom back to computing, via the bold:"LGPL" license, because a library is a library. + - A standard is not a true standard if it is not freely available and cannot be freely used or followed. + - Avoid the bold:"feature" trap where projects keep adding things. + - Provide an explicit versioning system that is more than a number, it communicates the status in a very simple manner. + - Continue mantaining major versions, a project should be able to last 20, 30, or even 60 years without breaking changes. + - Follow the KISS:"Keep It Simple Stupid", principles. + - Can be broken up into individual projects, and then further fine-tuned via custom define macros, so that only what is needed for specific situations need be used. + + The FLL:"Featureless Linux Library" versioning system has three parts: code:"major.minor.micro". + - The bold:"Major" is the primary API:"Application Programming Interface" specification, changes to this number represent massive breaking changes and for all intents and purposes is a different project. + - The bold:"Minor" represents potential breaking changes, where odd numbers represent bold:"development status" and even numbers represent bold:"stable status". + - The bold:"Micro" represents bug fixes and security fixes, these should never introduce neither API:"Application Programming Interface" breaking changes nor new functionality. + + Development releases (as specified by bold:"Minor" version part) may introduce breaking changes and new functionality. + Stable releases (as specified by the bold:"Minor" version part) may not introduce breaking change, unless forced by some security or other difficult situation, and must not add new functionality. + + The FLL:"Featureless Linux Library" project is broken up into 3 different levels: code:"level_0", code:"level_1", and code:"level_2". + A third pseudo-level also exists for common programs built using this project, called code:"level_3". + + With an exception of a few projects within code:"level_0", each level should only depend on a project from a lower level. + Therefore, a code:"level_1" project can only depend on code:"level_0" projects and a code:"level_2" project can depend on only code:"level_0" and code:"level_1" projects. + This does not technically apply to the pseudo-level, code:"level_3", projects, but the pattern is generally followed. + + A few projects in code:"level_0" are essentially required by everything and are depended on by virtually all projects, regardless of the level. + These code:"level_0" projects are\: + - code:"f_type": Provides core type definitions, code:"#define", and similar structures for the entire set of FLL:"Featureless Linux Library" projects. + - code:"f_status": provides status codes and other status codes to be used by the entire set of FLL:"Featureless Linux Library" projects. + - code:"f_memory": provides common memory allocation or deallocation to be used by the entire set of FLL:"Featureless Linux Library" projects. + - code:"f_type_array": provides an extension on code:"f_type" that requires linking to code:"f_memory" to be used by the entire set of FLL:"Featureless Linux Library" projects. + - code:"f_string": provides common string management to be used by the entire set of the FLL:"Featureless Linux Library" projects. + - code:"f_utf": provides common UTF-8 related string management to be used by the entire set of the FLL:"Featureless Linux Library" projects. + + The above projects should be installed first, and in the provided order (code:"f_type", then code:"f_status", then code:"f_memory", then code:"f_type_array", then code:"f_string", and finally code:"f_utf"). + No other code:"level_0" project should depend on another and can be installed in any order. + + To facilitate building of this project, two different build systems are provided\: + - The bootstrap, via the file:"bootstrap.sh" script. + - The bold:"Featureless Make", which is a level 3 project provided by FLL:"Featureless Linux Library". + + See: file:"data/build/dependencies" for specific dependencies of this project. + See: file:"documents/readme.bootstrap.txt" for bootstrap compiling (or just regular compiling) any part of the FLL:"Featureless Linux Library" and notes on installing. + See: file:"documents/readme.build.txt" for bold:"Featureless Make" compiling and notes on installing. diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..11c1b95 --- /dev/null +++ b/install.sh @@ -0,0 +1,881 @@ +#!/bin/bash +# license: lgpl-2.1-or-later +# programmer: Kevin Day +# +# The purpose of this script is to provide a simple installer tool to copy any part of the FLL project onto a system. +# This assumes the destination directories already exist and does not attempt to create them. +# Ideally, the package manager of the system should be used, but this is provided as a guide or a fallback. +# Settings files are not copied over, but a warning will be printed to inform the installer of their existence. +# +# The dependencies of this script are: bash, grep, and sed. +# +# This script can also be run under zsh rather than bash by setting the environment variable SHELL_ENGINE to "zsh", such as: +# SHELL_ENGINE="zsh" zsh ./install.sh --help +# + +install_main() { + local IFS=$' \t\n' # Prevent IFS exploits by overriding with a local scope. + + if [[ ${SHELL_ENGINE} == "zsh" ]] ; then + emulate ksh + fi + + local public_name="Simple FLL Project Install Script" + local system_name=install + local called_name=$(basename ${0}) + local version=0.7.3 + + local grab_next= + local do_color=dark + local do_help= + local do_copyright= + local i=0 + local p= + local t=0 + local key= + + local c_reset="\\033[0m" + local c_title="\\033[1;33m" + local c_error="\\033[1;31m" + local c_warning="\\033[0;33m" + local c_highlight="\\033[1;32m" + local c_notice="\\033[0;01m" + local c_important="\\033[0;32m" + local c_subtle="\\033[1;30m" + local c_prefix="\\" + + local failure=0 + local operation= + local operation_failure= + local verbosity=normal + local verbose= + local verbose_common= + + local path_build=build/ + local path_documentation=documentation/ + local path_programs=programs/ + local path_includes=includes/ + local path_libraries=libraries/ + local path_settings=settings/ + local path_static=static/ + local path_shared=shared/ + + local destination_documentation=share/ + local destination_prefix=/usr/local/ + local destination_programs=bin/ + local destination_includes=include/ + local destination_libraries=lib/ + local destination_libraries_static= + local destination_libraries_shared= + local destination_programs_static= + local destination_programs_shared= + local destination_settings=etc/ + + local work= + + local enable_documentation="yes" + local enable_settings="yes" + local enable_shared="yes" + local enable_shared_programs="yes" + local enable_shared_libraries="yes" + local enable_static="yes" + local enable_static_programs="yes" + local enable_static_libraries="yes" + local enable_includes="yes" + + if [[ ${#} -gt 0 ]] ; then + t=${#} + + while [[ ${i} -lt ${t} ]] ; do + let i=${i}+1 + + if [[ ${SHELL_ENGINE} == "zsh" ]] ; then + p=${(P)i} + else + p=${!i} + fi + + if [[ ${grab_next} == "" ]] ; then + if [[ ${p} == "-h" || ${p} == "--help" ]] ; then + do_help=yes + elif [[ ${p} == "+C" || ${p} == "++copyright" ]] ; then + do_copyright="yes" + elif [[ ${p} == "+d" || ${p} == "++dark" ]] ; then + do_color="dark" + context="+d" + elif [[ ${p} == "+l" || ${p} == "++light" ]] ; then + do_color="light" + context="+l" + elif [[ ${p} == "+n" || ${p} == "++no_color" ]] ; then + do_color=none + context="+n" + elif [[ ${p} == "+Q" || ${p} == "++quiet" ]] ; then + verbosity="quiet" + verbose="+Q" + verbose_common= + elif [[ ${p} == "+N" || ${p} == "++normal" ]] ; then + verbosity= + verbose="+N" + verbose_common= + elif [[ ${p} == "+E" || ${p} == "++error" ]] ; then + verbosity="error" + verbose="+E" + verbose_common= + elif [[ ${p} == "+V" || ${p} == "++verbose" ]] ; then + verbosity="verbose" + verbose="+V" + verbose_common="-v" + elif [[ ${p} == "+D" || ${p} == "++debug" ]] ; then + verbosity="debug" + verbose="+D" + verbose_common="-v" + elif [[ ${p} == "+v" || ${p} == "++version" ]] ; then + echo ${version} + return 0 + elif [[ ${p} == "-b" || ${p} == "--build" ]] ; then + grab_next=path_build + elif [[ ${p} == "-P" || ${p} == "--prefix" ]] ; then + grab_next=prefix + elif [[ ${p} == "-B" || ${p} == "--bindir" ]] ; then + grab_next=bindir + elif [[ ${p} == "-D" || ${p} == "--docdir" ]] ; then + grab_next=docdir + elif [[ ${p} == "-E" || ${p} == "--etcdir" ]] ; then + grab_next=etcdir + elif [[ ${p} == "-I" || ${p} == "--includedir" ]] ; then + grab_next=includedir + elif [[ ${p} == "-L" || ${p} == "--libdir" ]] ; then + grab_next=libdir + elif [[ ${p} == "-w" || ${p} == "--work" ]] ; then + grab_next=work + elif [[ ${p} == "--enable-doc" ]] ; then + enable_documentation="yes" + elif [[ ${p} == "--disable-doc" ]] ; then + enable_documentation="no" + elif [[ ${p} == "--enable-settings" ]] ; then + enable_settings="yes" + elif [[ ${p} == "--disable-settings" ]] ; then + enable_settings="no" + elif [[ ${p} == "--enable-shared" ]] ; then + enable_shared="yes" + elif [[ ${p} == "--disable-shared" ]] ; then + enable_shared="no" + elif [[ ${p} == "--disable-shared-programs" ]] ; then + enable_shared_programs="no" + elif [[ ${p} == "--disable-shared-libraries" ]] ; then + enable_shared_libraries="no" + elif [[ ${p} == "--disable-static-programs" ]] ; then + enable_static_programs="no" + elif [[ ${p} == "--disable-static-libraries" ]] ; then + enable_static_libraries="no" + elif [[ ${p} == "--enable-static" ]] ; then + enable_static="yes" + elif [[ ${p} == "--disable-static" ]] ; then + enable_static="no" + elif [[ ${p} == "--enable-includes" ]] ; then + enable_includes="yes" + elif [[ ${p} == "--disable-includes" ]] ; then + enable_includes="no" + elif [[ ${p} == "--libraries-static" ]] ; then + grab_next="destination_libraries_static" + elif [[ ${p} == "--libraries-shared" ]] ; then + grab_next="destination_libraries_shared" + elif [[ ${p} == "--programs-static" ]] ; then + grab_next="destination_programs_static" + elif [[ ${p} == "--programs-shared" ]] ; then + grab_next="destination_programs_shared" + elif [[ ${operation_failure} == "" ]] ; then + operation="${p}" + operation_failure=fail-unsupported + fi + else + if [[ ${grab_next} == "path_build" ]] ; then + path_build=$(sed -e 's|^//*|/|' -e 's|/*$|/|' <<< ${p}) + elif [[ ${grab_next} == "prefix" ]] ; then + destination_prefix=$(sed -e 's|^//*|/|' -e 's|/*$|/|' <<< ${p}) + elif [[ ${grab_next} == "bindir" ]] ; then + destination_programs=$(sed -e 's|^//*|/|' -e 's|/*$|/|' <<< ${p}) + elif [[ ${grab_next} == "docdir" ]] ; then + destination_documentation=$(sed -e 's|^//*|/|' -e 's|/*$|/|' <<< ${p}) + elif [[ ${grab_next} == "etcdir" ]] ; then + destination_settings=$(sed -e 's|^//*|/|' -e 's|/*$|/|' <<< ${p}) + elif [[ ${grab_next} == "includedir" ]] ; then + destination_includes=$(sed -e 's|^//*|/|' -e 's|/*$|/|' <<< ${p}) + elif [[ ${grab_next} == "libdir" ]] ; then + destination_libraries=$(sed -e 's|^//*|/|' -e 's|/*$|/|' <<< ${p}) + elif [[ ${grab_next} == "work" ]] ; then + work=$(sed -e 's|^//*|/|' -e 's|/*$|/|' <<< ${p}) + elif [[ ${grab_next} == "destination_libraries_static" ]] ; then + destination_libraries_static=$(sed -e 's|^//*|/|' -e 's|/*$|/|' <<< ${p}) + elif [[ ${grab_next} == "destination_libraries_shared" ]] ; then + destination_libraries_shared=$(sed -e 's|^//*|/|' -e 's|/*$|/|' <<< ${p}) + elif [[ ${grab_next} == "destination_programs_static" ]] ; then + destination_programs_static=$(sed -e 's|^//*|/|' -e 's|/*$|/|' <<< ${p}) + elif [[ ${grab_next} == "destination_programs_shared" ]] ; then + destination_programs_shared=$(sed -e 's|^//*|/|' -e 's|/*$|/|' <<< ${p}) + fi + + grab_next= + fi + done + + p= + fi + + install_handle_colors + + if [[ ${do_help} == "yes" ]] ; then + install_help + install_cleanup + + return 0 + fi + + if [[ ${do_copyright} == "yes" ]] ; then + install_copyright + install_cleanup + + return 0 + fi + + if [[ ${operation_failure} == "fail-unsupported" ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: The operation ${c_notice}${operation}${c_error} was not recognized.${c_reset}" + fi + + install_cleanup + + return 1 + fi + + if [[ ! -d ${path_build} ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: The build path ${c_notice}${path_build}${c_error} is not a valid directory.${c_reset}" + fi + + install_cleanup + + return 1 + fi + + if [[ ${work} == "" && ${destination_prefix} != "" && ! -d ${destination_prefix} ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: The destination prefix ${c_notice}${destination_prefix}${c_error} is not a valid directory.${c_reset}" + fi + + install_cleanup + + return 1 + fi + + if [[ ${destination_prefix} != "" ]] ; then + if [[ $(grep -sho '^/' <<< ${destination_documentation}) == "" ]] ; then + destination_documentation="${destination_prefix}${destination_documentation}" + fi + + if [[ $(grep -sho '^/' <<< ${destination_programs}) == "" ]] ; then + destination_programs="${destination_prefix}${destination_programs}" + fi + + if [[ $(grep -sho '^/' <<< ${destination_includes}) == "" ]] ; then + destination_includes="${destination_prefix}${destination_includes}" + fi + + if [[ $(grep -sho '^/' <<< ${destination_libraries}) == "" ]] ; then + destination_libraries="${destination_prefix}${destination_libraries}" + fi + + if [[ $(grep -sho '^/' <<< ${destination_settings}) == "" ]] ; then + destination_settings="${destination_prefix}${destination_settings}" + fi + fi + + if [[ ${destination_libraries_static} != "" ]] ; then + if [[ $(grep -sho '^/' <<< ${destination_libraries_static}) == "" ]] ; then + destination_libraries_static=${destination_libraries}${destination_libraries_static} + fi + else + destination_libraries_static=${destination_libraries} + fi + + if [[ ${destination_libraries_shared} != "" ]] ; then + if [[ $(grep -sho '^/' <<< ${destination_libraries_shared}) == "" ]] ; then + destination_libraries_shared=${destination_libraries}${destination_libraries_shared} + fi + else + destination_libraries_shared=${destination_libraries} + fi + + if [[ ${destination_programs_static} != "" ]] ; then + if [[ $(grep -sho '^/' <<< ${destination_programs_static}) == "" ]] ; then + destination_programs_static=${destination_programs}${destination_programs_static} + fi + else + destination_programs_static=${destination_programs} + fi + + if [[ ${destination_programs_shared} != "" ]] ; then + if [[ $(grep -sho '^/' <<< ${destination_programs_shared}) == "" ]] ; then + destination_programs_shared=${destination_programs}${destination_programs_shared} + fi + else + destination_programs_shared=${destination_programs} + fi + + if [[ ${work} != "" && ! -d ${work} ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: The work directory ${c_notice}${work}${c_error} is not a valid directory.${c_reset}" + fi + + install_cleanup + + return 1 + fi + + if [[ ${work} == "" && -e ${destination_programs} && ! -d ${destination_programs} ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: The destination bindir ${c_notice}${destination_programs}${c_error} is not a valid directory.${c_reset}" + fi + + install_cleanup + + return 1 + fi + + if [[ ${work} == "" && -e ${destination_programs_static} && ! -d ${destination_programs_static} ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: The destination (${c_notice}static${c_error}) bindir ${c_notice}${destination_programs_static}${c_error} is not a valid directory.${c_reset}" + fi + + install_cleanup + + return 1 + fi + + if [[ ${work} == "" && -e ${destination_programs_shared} && ! -d ${destination_programs_shared} ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: The destination (${c_notice}shared${c_error}) bindir ${c_notice}${destination_programs_shared}${c_error} is not a valid directory.${c_reset}" + fi + + install_cleanup + + return 1 + fi + + if [[ ${work} == "" && -e ${destination_includes} && ! -d ${destination_includes} ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: The destination incluedir ${c_notice}${destination_includes}${c_error} is not a valid directory.${c_reset}" + fi + + install_cleanup + + return 1 + fi + + if [[ ${work} == "" && -e ${destination_libraries_static} && ! -d ${destination_libraries_static} ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: The destination (${c_notice}static${c_error}) libdir ${c_notice}${destination_libraries_static}${c_error} is not a valid directory.${c_reset}" + fi + + install_cleanup + + return 1 + fi + + if [[ ${work} == "" && -e ${destination_libraries_shared} && ! -d ${destination_libraries_shared} ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: The destination (${c_notice}shared${c_error}) libdir ${c_notice}${destination_libraries_shared}${c_error} is not a valid directory.${c_reset}" + fi + + install_cleanup + + return 1 + fi + + install_perform_install + + install_cleanup + + if [[ ${failure} -eq 1 ]] ; then + return 1 + fi + + return 0 +} + +install_handle_colors() { + + if [[ ${do_color} == "light" ]] ; then + c_error="\\033[1;31m" + c_warning="\\033[0;31m" + c_title="\\033[1;34m" + c_highlight="\\033[0;34m" + c_notice="\\033[0;01m" + c_important="\\033[0;35m" + elif [[ ${do_color} == "none" ]] ; then + c_reset= + c_title= + c_error= + c_warning= + c_highlight= + c_notice= + c_important= + c_subtle= + c_prefix= + fi +} + +install_help() { + + echo -e "${c_title}${public_name}${c_reset}" + echo -e " ${c_notice}Version ${version}${c_reset}" + echo + echo -e "${c_highlight}${system_name}${c_reset} ${c_notice}[${c_reset} options ${c_notice}]${c_reset}" + echo + echo -e "${c_highlight}Options:${c_reset}" + echo -e " -${c_important}h${c_reset}, --${c_important}help${c_reset} Print this help message." + echo -e " +${c_important}C${c_reset}, ++${c_important}copyright${c_reset} Print the copyright." + echo -e " +${c_important}d${c_reset}, ++${c_important}dark${c_reset} Output using colors that show up better on dark backgrounds." + echo -e " +${c_important}l${c_reset}, ++${c_important}light${c_reset} Output using colors that show up better on light backgrounds." + echo -e " +${c_important}n${c_reset}, ++${c_important}no_color${c_reset} Do not print using color." + echo -e " +${c_important}Q${c_reset}, ++${c_important}quiet${c_reset} Decrease verbosity, silencing most print.to." + echo -e " +${c_important}E${c_reset}, ++${c_important}error${c_reset} Decrease verbosity, using only error print.to." + echo -e " +${c_important}N${c_reset}, ++${c_important}normal${c_reset} Set verbosity to normal." + echo -e " +${c_important}V${c_reset}, ++${c_important}verbose${c_reset} Increase verbosity beyond normal print.to." + echo -e " +${c_important}D${c_reset}, ++${c_important}debug${c_reset} Enable debugging, significantly increasing verbosity beyond normal print.to." + echo -e " +${c_important}v${c_reset}, ++${c_important}version${c_reset} Print only the version number." + echo + echo -e "${c_highlight}Install Options:${c_reset}" + echo -e " -${c_important}b${c_reset}, --${c_important}build${c_reset} Custom build directory." + echo -e " -${c_important}P${c_reset}, --${c_important}prefix${c_reset} Custom destination prefix." + echo -e " -${c_important}B${c_reset}, --${c_important}bindir${c_reset} Custom destination bin/ directory." + echo -e " -${c_important}D${c_reset}, --${c_important}docdir${c_reset} Custom destination share/ directory (documentation directory)." + echo -e " -${c_important}E${c_reset}, --${c_important}etcdir${c_reset} Custom destination etc/ directory (settings directory)." + echo -e " -${c_important}I${c_reset}, --${c_important}includedir${c_reset} Custom destination include/ directory." + echo -e " -${c_important}L${c_reset}, --${c_important}libdir${c_reset} Custom destination lib/ directory." + echo -e " -${c_important}w${c_reset}, --${c_important}work${c_reset} Install to this work directory using a 'working' directory structure." + echo + echo -e "${c_highlight}Special Options:${c_reset}" + echo -e " --${c_important}enable-doc${c_reset} Forcibly do install documentation files." + echo -e " --${c_important}disable-doc${c_reset} Forcibly do not install documentation files." + echo -e " --${c_important}enable-settings${c_reset} Forcibly do install settings files." + echo -e " --${c_important}disable-settings${c_reset} Forcibly do not install settings files." + echo -e " --${c_important}enable-shared${c_reset} Forcibly do install shared files." + echo -e " --${c_important}disable-shared${c_reset} Forcibly do not install shared files." + echo -e " --${c_important}disable-shared-programs${c_reset} Forcibly do not install shared programs." + echo -e " --${c_important}disable-shared-libraries${c_reset} Forcibly do not install shared libraries." + echo -e " --${c_important}enable-static${c_reset} Forcibly do install static files." + echo -e " --${c_important}disable-static${c_reset} Forcibly do not install static files." + echo -e " --${c_important}disable-static-programs${c_reset} Forcibly do not install shared programs." + echo -e " --${c_important}disable-static-libraries${c_reset} Forcibly do not install shared libraries." + echo -e " --${c_important}enable-includes${c_reset} Forcibly do not install include files." + echo -e " --${c_important}disable-includes${c_reset} Forcibly do not install include files." + echo -e " --${c_important}libraries-static${c_reset} Custom destination for static libraries." + echo -e " --${c_important}libraries-shared${c_reset} Custom destination for shared libraries." + echo -e " --${c_important}programs-static${c_reset} Custom destination for static programs." + echo -e " --${c_important}programs-shared${c_reset} Custom destination for shared programs." +} + +install_copyright() { + + echo "Copyright © 2007-2025 Kevin Day." + echo + echo "Source code license lgpl-2.1-or-later." + echo "Standard and specification license open-standard-license-1.0-or-later." + echo "Documentation license cc-by-sa-4.0." +} + +install_perform_install() { + local key= + local i= + local path= + local message= + + if [[ ${enable_shared} == "no" ]] ; then + enable_shared_programs="no" + enable_shared_libraries="no" + fi + + if [[ ${enable_static} == "no" ]] ; then + enable_static_programs="no" + enable_static_libraries="no" + fi + + if [[ ${work} == "" ]] ; then + message="install destination directory" + else + message="work directory" + destination_prefix=${work} + destination_documentation=${work}documentation/ + destination_programs=${work}programs/ + destination_programs_static=${destination_programs}static/ + destination_programs_shared=${destination_programs}shared/ + destination_includes=${work}includes/ + destination_libraries=${work}libraries/ + destination_libraries_static=${destination_libraries}static/ + destination_libraries_shared=${destination_libraries}shared/ + destination_settings=${work}settings/ + fi + + if [[ ! -d ${destination_prefix} ]] ; then + mkdir ${verbose_common} ${destination_prefix} + + if [[ ${?} -ne 0 ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: Failed to create install ${message} ${c_notice}${destination_prefix}${c_error}.${c_reset}" + fi + + let failure=1 + fi + fi + + if [[ ${enable_shared_programs} == "yes" || ${enable_static_programs} == "yes" ]] ; then + if [[ -d ${path_build}${path_programs} && ! -d ${destination_programs} ]] ; then + mkdir ${verbose_common} ${destination_programs} + + if [[ ${?} -ne 0 ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: Failed to create install ${message} ${c_notice}${destination_programs}${c_error}.${c_reset}" + fi + + let failure=1 + fi + fi + + if [[ ${enable_shared_programs} == "yes" && -d ${path_build}${path_programs}${path_shared} && ! -d ${destination_programs_shared} ]] ; then + mkdir ${verbose_common} ${destination_programs_shared} + + if [[ ${?} -ne 0 ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: Failed to create install ${message} ${c_notice}${destination_programs_shared}${c_error}.${c_reset}" + fi + + let failure=1 + fi + fi + + if [[ ${enable_static_programs} == "yes" && -d ${path_build}${path_programs}${path_static} && ! -d ${destination_programs_static} ]] ; then + mkdir ${verbose_common} ${destination_programs_static} + + if [[ ${?} -ne 0 ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: Failed to create install ${message} ${c_notice}${destination_programs_static}${c_error}.${c_reset}" + fi + + let failure=1 + fi + fi + fi + + if [[ ${enable_shared_libraries} == "yes" || ${enable_static_libraries} == "yes" ]] ; then + if [[ -d ${path_build}${path_libraries} && ! -d ${destination_libraries} ]] ; then + mkdir ${verbose_common} ${destination_libraries} + + if [[ ${?} -ne 0 ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: Failed to create install ${message} ${c_notice}${destination_libraries}${c_error}.${c_reset}" + fi + + let failure=1 + fi + fi + + if [[ ${enable_shared_libraries} == "yes" && -d ${path_build}${path_libraries}${path_shared} && ! -d ${destination_libraries_shared} ]] ; then + mkdir ${verbose_common} ${destination_libraries_shared} + + if [[ ${?} -ne 0 ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: Failed to create ${message} ${c_notice}${destination_libraries_shared}${c_error}.${c_reset}" + fi + + let failure=1 + fi + fi + + if [[ ${enable_static_libraries} == "yes" && -d ${path_build}${path_libraries}${path_static} && ! -d ${destination_libraries_static} ]] ; then + mkdir ${verbose_common} ${destination_libraries_static} + + if [[ ${?} -ne 0 ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: Failed to create ${message} ${c_notice}${destination_libraries_static}${c_error}.${c_reset}" + fi + + let failure=1 + fi + fi + fi + + if [[ ${enable_includes} == "yes" ]] ; then + if [[ -d ${path_build}${path_includes} && ! -d ${destination_includes} ]] ; then + mkdir ${verbose_common} ${destination_includes} + + if [[ ${?} -ne 0 ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: Failed to create ${message} ${c_notice}${destination_includes}${c_error}.${c_reset}" + fi + + let failure=1 + fi + fi + fi + + if [[ ${enable_documentation} == "yes" ]] ; then + if [[ -d ${path_build}${path_documentation} && ! -d ${destination_documentation} ]] ; then + mkdir ${verbose_common} ${destination_documentation} + + if [[ ${?} -ne 0 ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: Failed to create ${message} ${c_notice}${destination_documentation}${c_error}.${c_reset}" + fi + + let failure=1 + fi + fi + fi + + if [[ ${enable_settings} == "yes" ]] ; then + if [[ -d ${path_build}${path_settings} && ! -d ${destination_settings} ]] ; then + mkdir ${verbose_common} ${destination_settings} + + if [[ ${?} -ne 0 ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: Failed to create ${message} ${c_notice}${destination_settings}${c_error}.${c_reset}" + fi + + let failure=1 + fi + fi + fi + + if [[ ${failure} -eq 0 && -d ${path_build}${path_includes} && ${enable_includes} == "yes" ]] ; then + for i in ${path_build}${path_includes}* ; do + + file=$(sed -e "s|^${path_build}${path_includes}||" <<< ${i}) + + break + done + + if [[ ${file} == "*" && ! -f "${path_build}${path_includes}*" ]] ; then + file= + fi + + if [[ ${file} != "" ]] ; then + if [[ ${verbosity} != "quiet" && ${verbosity} != "error" ]] ; then + echo + echo -e "${c_highlight}Installing Includes to: ${c_reset}${c_notice}${destination_includes}${c_reset}${c_highlight}.${c_reset}" + fi + + cp ${verbose_common} -R ${path_build}${path_includes}* ${destination_includes} + + if [[ ${?} -ne 0 ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: Failed to copy include files from ${c_notice}${path_build}${path_includes}${c_error} to ${c_notice}${destination_includes}${c_error}.${c_reset}" + fi + + let failure=1 + fi + fi + fi + + if [[ ${failure} -eq 0 && -d ${path_build}${path_libraries} && ( ${enable_shared_libraries} == "yes" || ${enable_static_libraries} == "yes" ) ]] ; then + if [[ -d ${path_build}${path_libraries}${path_static} && ${enable_static_libraries} == "yes" ]] ; then + for i in ${path_build}${path_libraries}${path_static}* ; do + + file=$(sed -e "s|^${path_build}${path_libraries}${path_static}||" <<< ${i}) + + break + done + + if [[ ${file} == "*" && ! -f "${path_build}${path_libraries}${path_static}*" ]] ; then + file= + fi + + if [[ ${file} != "" ]] ; then + if [[ ${verbosity} != "quiet" && ${verbosity} != "error" ]] ; then + echo + echo -e "${c_highlight}Installing (${c_notice}static${c_highlight}) Libraries to: ${c_reset}${c_notice}${destination_libraries_static}${c_reset}${c_highlight}.${c_reset}" + fi + + cp ${verbose_common} -R ${path_build}${path_libraries}${path_static}* ${destination_libraries_static} + + if [[ ${?} -ne 0 ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: Failed to copy (${c_notice}static${c_error}) library files from ${c_notice}${path_build}${path_libraries}${path_static}${c_error} to ${c_notice}${destination_libraries_static}${c_error}.${c_reset}" + fi + + let failure=1 + fi + fi + fi + + if [[ ${failure} -eq 0 && -d ${path_build}${path_libraries}${path_shared} && ${enable_shared_libraries} == "yes" ]] ; then + for i in ${path_build}${path_libraries}${path_shared}* ; do + + file=$(sed -e "s|^${path_build}${path_libraries}${path_shared}||" <<< ${i}) + + break + done + + if [[ ${file} == "*" && ! -f "${path_build}${path_libraries}${path_shared}*" ]] ; then + file= + fi + + if [[ ${file} != "" ]] ; then + if [[ ${verbosity} != "quiet" && ${verbosity} != "error" ]] ; then + echo + echo -e "${c_highlight}Installing (${c_notice}shared${c_highlight}) Libraries to: ${c_reset}${c_notice}${destination_libraries_shared}${c_reset}${c_highlight}.${c_reset}" + fi + + cp ${verbose_common} -R ${path_build}${path_libraries}${path_shared}* ${destination_libraries_shared} + + if [[ ${?} -ne 0 ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: Failed to copy (${c_notice}shared${c_error}) library files from ${c_notice}${path_build}${path_libraries}${path_shared}${c_error} to ${c_notice}${destination_libraries_shared}${c_error}.${c_reset}" + fi + + let failure=1 + fi + fi + fi + fi + + if [[ ${failure} -eq 0 && -d ${path_build}${path_programs} && ( ${enable_shared_programs} == "yes" || ${enable_static_programs} == "yes" ) ]] ; then + if [[ -d ${path_build}${path_programs}${path_static} && ${enable_static_programs} == "yes" ]] ; then + for i in ${path_build}${path_programs}${path_static}* ; do + + file=$(sed -e "s|^${path_build}${path_programs}${path_static}||" <<< ${i}) + + break + done + + if [[ ${file} == "*" && ! -f "${path_build}${path_programs}${path_static}*" ]] ; then + file= + fi + + if [[ ${file} != "" && ${enable_static_programs} == "yes" ]] ; then + if [[ ${verbosity} != "quiet" && ${verbosity} != "error" ]] ; then + echo + echo -e "${c_highlight}Installing (${c_notice}static${c_highlight}) Programs to: ${c_reset}${c_notice}${destination_programs_static}${c_reset}${c_highlight}.${c_reset}" + fi + + cp ${verbose_common} -R ${path_build}${path_programs}${path_static}* ${destination_programs_static} + + if [[ ${?} -ne 0 ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: failed to copy (${c_notice}static${c_error}) program files from ${c_notice}${path_build}${path_programs}${path_static}${c_error} to ${c_notice}${destination_programs_static}${c_error}.${c_reset}" + fi + + let failure=1 + fi + fi + fi + + if [[ ${failure} -eq 0 && -d ${path_build}${path_programs}${path_shared} && ${enable_shared_programs} == "yes" ]] ; then + for i in ${path_build}${path_programs}${path_shared}* ; do + + file=$(sed -e "s|^${path_build}${path_programs}${path_shared}||" <<< ${i}) + + break + done + + if [[ ${file} == "*" && ! -f "${path_build}${path_programs}${path_shared}*" ]] ; then + file= + fi + + if [[ ${file} != "" ]] ; then + if [[ ${verbosity} != "quiet" && ${verbosity} != "error" ]] ; then + echo + echo -e "${c_highlight}Installing (${c_notice}shared${c_highlight}) Programs to: ${c_reset}${c_notice}${destination_programs_shared}${c_reset}${c_highlight}.${c_reset}" + fi + + cp ${verbose_common} -R ${path_build}${path_programs}${path_shared}* ${destination_programs_shared} + + if [[ ${?} -ne 0 ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: failed to copy (${c_notice}shared${c_error}) program files from ${c_notice}${path_build}${path_programs}${path_shared}${c_error} to ${c_notice}${destination_programs_shared}${c_error}.${c_reset}" + fi + + let failure=1 + fi + fi + fi + fi + + if [[ ${failure} -eq 0 && -d ${path_build}${path_settings} && ${enable_settings} == "yes" ]] ; then + for i in ${path_build}${path_settings}* ; do + + file=$(sed -e "s|^${path_build}${path_settings}||" <<< ${i}) + + break + done + + if [[ ${file} == "*" && ! -f "${path_build}${path_settings}*" ]] ; then + file= + fi + + if [[ ${file} != "" ]] ; then + if [[ ${verbosity} != "quiet" && ${verbosity} != "error" ]] ; then + echo + echo -e "${c_highlight}Installing Settings to: ${c_reset}${c_notice}${destination_settings}${c_reset}${c_highlight}.${c_reset}" + fi + + cp ${verbose_common} -R ${path_build}${path_settings}* ${destination_settings} + + if [[ ${?} -ne 0 ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: failed to copy settings files from ${c_notice}${path_build}${path_settings}${c_error} to ${c_notice}${destination_settings}${c_error}.${c_reset}" + fi + + let failure=1 + fi + fi + fi + + if [[ ${failure} -eq 0 && -d ${path_build}${path_documentation} && ${enable_documentation} == "yes" ]] ; then + for i in ${path_build}${path_documentation}* ; do + + file=$(sed -e "s|^${path_build}${path_documentation}||" <<< ${i}) + + break + done + + if [[ ${file} == "*" && ! -f "${path_build}${path_documentation}*" ]] ; then + file= + fi + + if [[ ${file} != "" ]] ; then + if [[ ${verbosity} != "quiet" && ${verbosity} != "error" ]] ; then + echo + echo -e "${c_highlight}Installing Documentation to: ${c_reset}${c_notice}${destination_documentation}${c_reset}${c_highlight}.${c_reset}" + fi + + cp ${verbose_common} -R ${path_build}${path_documentation}* ${destination_documentation} + + if [[ ${?} -ne 0 ]] ; then + if [[ ${verbosity} != "quiet" ]] ; then + echo -e "${c_error}ERROR: failed to copy documentation files from ${c_notice}${path_build}${path_documentation}${c_error} to ${c_notice}${destination_documentation}${c_error}.${c_reset}" + fi + + let failure=1 + fi + fi + fi + + if [[ ${failure} -eq 1 ]] ; then + return 1 + fi + + return 0 +} + +install_cleanup() { + + unset install_copyright + unset install_main + unset install_handle_colors + unset install_help + unset install_perform_install + unset install_cleanup +} + +install_main ${*} diff --git a/licenses/cc-by-sa-4.0 b/licenses/cc-by-sa-4.0 new file mode 100644 index 0000000..e672f4e --- /dev/null +++ b/licenses/cc-by-sa-4.0 @@ -0,0 +1,4 @@ +Creative Commons Attribution Share Alike 4.0 International + +see: https://creativecommons.org/licenses/by-sa/4.0/ +see: https://creativecommons.org/licenses/by-sa/4.0/legalcode diff --git a/licenses/copyrights.txt b/licenses/copyrights.txt new file mode 100644 index 0000000..9edb5dc --- /dev/null +++ b/licenses/copyrights.txt @@ -0,0 +1,5 @@ +ALl files within this project unless otherwise specified are Copyright © 2007-2025 Kevin Day. + +Source code and related files are under lgpl-2.1-or-later. +Specifications and related files are under open-standard-license-1.0-or-later. +Documentation and related files are under cc-by-sa-4.0. diff --git a/licenses/lgpl-2.1-or-later b/licenses/lgpl-2.1-or-later new file mode 100644 index 0000000..602bfc9 --- /dev/null +++ b/licenses/lgpl-2.1-or-later @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/licenses/open-standard-license-1.0-or-later b/licenses/open-standard-license-1.0-or-later new file mode 100644 index 0000000..d82c79d --- /dev/null +++ b/licenses/open-standard-license-1.0-or-later @@ -0,0 +1,44 @@ +Open Standard License 1.0. + February 27, 2024. + +This license applies to the Standards and their Specifications and designates legal requirements on Implementations of the Standard and their respective Specifications. + +Terminology: + - Standard: A set of rules and guidelines. + - Specification: A specific interpretation or clarification of a Standard, such as the documentation that describes how to use or follow a Standard. + - Implementation: The applying of some Standard or Specification. + - API: Application Programming Interface*. + - ABI: Application Binary Interface**. + - Service: Any action or labor performed by one party for another party (such as one person helping another person). + - Protocol: In the context of computers and software, this is a Standard focused on communication between at least two parties (often referring to Internet communication) and is at the most basic level an agreement of rules between two (or more) parties. + - Provider: A party who provides a Service of any kind (or equivalent functionality) that utilizes a Protocol or provides a Service that Implements or follows a Standard or Specification to another party. + +* The API term is commonly mis-represented as Services or Protocols (such as "Web API" which in actuality should be called "Web Service" or "Web Protocol"). + An API instructs a party, usually a programmer, on how to use a dependency when programming some software that utilizes said dependency. + An API is a Specification of some Implementation of a Standard be it a formally defined Standard or an informally defined Standard. + An API may be an Implementation of a Standard or a part of an Implementation of a Standard. + An API is, in effect, documentation. + +** The ABI term refers to an Application Binary Interface and represents the compiled Implementation of some API. + An ABI may not always exist for some API, such as for pure scripting languages. + An ABI is neither a Specification nor a Standard. + An ABI is an Implementation of an API making it an Implementation of a Standard or Specification. + +01) Principles of this license: + 01) The Standard or Specification is and must be freely and publicly available to use and implement irrespective of any license, patent, or other restriction of any kind for any reason of some Implementation or Provider. + 02) All patents associated are and must be royalty-free for unrestricted use and must not impose any restrictions on any third party's Implementation of this Standard in any way for any reason beyond those described in this license. + 03) There are not and there must not be any agreements or requirements for the execution of this license grant, including but not limited to: NDA, grant, click-through, or any form of paperwork (including but not limited to all non-paper forms of paperwork, such as digital forms). + 04) There are not and must not be any restrictions on the form of an Implementation of a Standard or Specification. + 05) Implementations of a Standard or Specification may be under any license so long as that license: + a) Does not restrict, alter, or invalidate this license in any manner. + b) Does not impose any form of restrictions to access, to use, to implement, to extend, or to deviate from anything allowed or otherwise granted by this license. + 06) This license shall prohibit any form of restricting any parties to access, to use, to implement, to extend, or o deviate from this Standard unless: + a) Restricted by this license. + b) Unless there is a breach of license conditions. + 07) This license is irrevocable unless there is a breach of the license conditions. + 08) This license does not grant any kind of warranty or liability under any circumstances to any party for any reason, be it direct, indirect, consequential, incidental, or in any other form. + 09) This license does not restrict any party from optionally providing their own warranty or liability on any Implementation but such warranties or liabilities are completely separate and independent of this license in all circumstances for any reason, be it direct, indirect, consequential, incidental, or for any other reason. + 10) The final and absolute determination of any terminology and intent of this license is by the original owner of this license or a party explicitly authorized by the original license owner or party, and is not in any way subject to re-interpretation or re-definition in any way for any reason by any party including but not limited to judges, juries, lawyers, attorneys, technicians, experts, or governments. + 11) Any restriction, alteration, removal, invalidation, making illegal, or making unlawful of or against any part of this license by any party, such as but not limited to a government or judge, shall not permanently alter this license in any way for any reason. That is for example, if some court deems some part of this unlawful and then later makes it lawful, then the now re-lawfulized parts do and must immediately apply once more as if it were never made unlawful. + 12) When at any point in time under any government any parts of this license is restricted, altered, removed, invalidated or otherwise made illegal, unlawful, or unenforceable is reversed, restored, or otherwise made legal, lawful, and enforceable again, then these parts are immediately in affect again. + 13) If at any point in time some party, such as but not limited to a government, makes any change to this license (like those described in [01.11]) and the licensee for any reason at any time is no longer subject to a given jurisdiction, then those parts of the original license are immediately in effect as if they were never altered or restricted in the first place. For example, if a licensee leaves the jurisdiction of some government that otherwise restricted some part of this license then that otherwise restricted part is immediately in affect again now that the licensee is out of the given jurisdiction. diff --git a/sources/c/config.c b/sources/c/config.c new file mode 100644 index 0000000..6ac629b --- /dev/null +++ b/sources/c/config.c @@ -0,0 +1,2 @@ + +#include "config.h" diff --git a/sources/c/config.h b/sources/c/config.h new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/sources/c/config.h @@ -0,0 +1 @@ + diff --git a/sources/c/main/common.c b/sources/c/main/common.c new file mode 100644 index 0000000..2bdae6a --- /dev/null +++ b/sources/c/main/common.c @@ -0,0 +1,157 @@ +#include "firewall.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_firewall_setting_load_ + void firewall_setting_load(const f_console_arguments_t arguments, firewall_main_t * const main) { + + if (!main) return; + + f_console_parameters_t * const parameters = &main->program.parameters; + + main->setting.state.step_small = firewall_allocation_console_d; + + f_console_parameter_process(arguments, parameters, &main->setting.state, 0); + + main->setting.state.step_small = firewall_allocation_small_d; + + if (F_status_is_error(main->setting.state.status)) { + firewall_print_error(&main->program.error, F_status_debug_source_d); + + return; + } + + main->setting.state.status = fll_program_parameter_process_context_standard(F_true, &main->program); + + if (F_status_is_error(main->setting.state.status)) { + firewall_print_error(&main->program.error, F_status_debug_source_d); + + return; + } + + main->setting.state.status = fll_program_parameter_process_verbosity_standard(F_true, &main->program); + + if (F_status_is_error(main->setting.state.status)) { + firewall_print_error(&main->program.error, F_status_debug_source_d); + + return; + } + + if (parameters->array[f_console_standard_parameter_help_e].result & f_console_result_found_d) { + main->setting.flag |= firewall_main_flag_help_d; + + return; + } + + if (parameters->array[f_console_standard_parameter_version_e].result & f_console_result_found_d) { + main->setting.flag |= firewall_main_flag_version_d; + + return; + } + + if (parameters->array[f_console_standard_parameter_copyright_e].result & f_console_result_found_d) { + main->setting.flag |= firewall_main_flag_copyright_d; + + return; + } + + f_number_unsigned_t index = 0; + + if (parameters->array[firewall_parameter_operation_start_e].result & f_console_result_found_d) { + main->setting.flag &= ~firewall_main_flag_operation_d; + main->setting.flag |= firewall_main_flag_operation_start_d; + + index = parameters->array[firewall_parameter_operation_start_e].location; + } + + if (parameters->array[firewall_parameter_operation_stop_e].result & f_console_result_found_d) { + if (!(main->setting.flag & firewall_main_flag_operation_d) || parameters->array[firewall_parameter_operation_stop_e].location > index) { + main->setting.flag &= ~firewall_main_flag_operation_d; + main->setting.flag |= firewall_main_flag_operation_stop_d; + + index = parameters->array[firewall_parameter_operation_stop_e].location; + } + } + + if (parameters->array[firewall_parameter_operation_restart_e].result & f_console_result_found_d) { + if (!(main->setting.flag & firewall_main_flag_operation_d) || parameters->array[firewall_parameter_operation_restart_e].location > index) { + main->setting.flag &= ~firewall_main_flag_operation_d; + main->setting.flag |= firewall_main_flag_operation_restart_d; + + index = parameters->array[firewall_parameter_operation_restart_e].location; + } + } + + if (parameters->array[firewall_parameter_operation_lock_e].result & f_console_result_found_d) { + if (!(main->setting.flag & firewall_main_flag_operation_d) || parameters->array[firewall_parameter_operation_lock_e].location > index) { + main->setting.flag &= ~firewall_main_flag_operation_d; + main->setting.flag |= firewall_main_flag_operation_lock_d; + + index = parameters->array[firewall_parameter_operation_lock_e].location; + } + } + + if (parameters->array[firewall_parameter_operation_show_e].result & f_console_result_found_d) { + if (!(main->setting.flag & firewall_main_flag_operation_d) || parameters->array[firewall_parameter_operation_show_e].location > index) { + main->setting.flag &= ~firewall_main_flag_operation_d; + main->setting.flag |= firewall_main_flag_operation_show_d; + } + } + + if (parameters->array[firewall_parameter_4_e].result & f_console_result_found_d) { + if (parameters->array[firewall_parameter_6_e].result & f_console_result_found_d) { + main->setting.flag |= firewall_main_flag_ipv46_d; + } + else { + main->setting.flag &= ~firewall_main_flag_ipv6_d; + main->setting.flag |= firewall_main_flag_ipv4_d; + } + } + else if (parameters->array[firewall_parameter_6_e].result & f_console_result_found_d) { + main->setting.flag &= ~firewall_main_flag_ipv4_d; + main->setting.flag |= firewall_main_flag_ipv6_d; + } + + if (main->program.pipe & fll_program_data_pipe_input_e) { + main->setting.flag |= firewall_main_flag_pipe_d; + } + else { + main->setting.flag &= ~firewall_main_flag_pipe_d; + } + + if (main->setting.flag & firewall_main_flag_operation_show_d) { + if (parameters->remaining.used) { + main->setting.flag &= ~firewall_main_flag_operation_show_filter_nat_mangle_d; + + for (f_number_unsigned_t i = 0; i < parameters->remaining.used; ++i) { + + if (macro_firewall_signal_check(&main->program, &main->setting.state)) return; + + index = parameters->remaining.array[i]; + + if (f_compare_dynamic(firewall_show_nat_s, parameters->arguments.array[index]) == F_equal_to) { + main->setting.flag |= firewall_main_flag_operation_show_nat_d; + } + else if (f_compare_dynamic(firewall_show_mangle_s, parameters->arguments.array[index]) == F_equal_to) { + main->setting.flag |= firewall_main_flag_operation_show_mangle_d; + } + else if (f_compare_dynamic(firewall_show_filter_s, parameters->arguments.array[index]) == F_equal_to) { + main->setting.flag |= firewall_main_flag_operation_show_filter_d; + } + else { + firewall_print_warning_show_option_unknown(&main->program.warning, parameters->arguments.array[index]); + } + } // for + } + else { + main->setting.flag |= firewall_main_flag_operation_show_filter_nat_mangle_d; + } + } + } +#endif // _di_firewall_setting_load_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/main/common.h b/sources/c/main/common.h new file mode 100644 index 0000000..27df97d --- /dev/null +++ b/sources/c/main/common.h @@ -0,0 +1,48 @@ +/** + * FLL - Level 3 + * + * Project: Firewall + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Provides the common data structures. + * + * This is auto-included and should not need to be explicitly included. + */ +#ifndef _firewall_common_h +#define _firewall_common_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Perform the standard program setting load process. + * + * This prints error messages as appropriate. + * + * If either main or setting is NULL, then this immediately returns without doing anything. + * + * @param arguments + * The parameters passed to the process (often referred to as command line arguments). + * @param main + * The main program data and settings. + * + * This alters main.setting.state.status: + * F_okay on success. + * + * Errors (with error bit) from: f_console_parameter_process(). + * Errors (with error bit) from: fll_program_parameter_process_context_standard(). + * + * @see f_console_parameter_process() + * @see fll_program_parameter_process_context_standard() + */ +#ifndef _di_firewall_setting_load_ + extern void firewall_setting_load(const f_console_arguments_t arguments, firewall_main_t * const main); +#endif // _di_firewall_setting_load_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _firewall_common_h diff --git a/sources/c/main/common/define.c b/sources/c/main/common/define.c new file mode 100644 index 0000000..9bcd373 --- /dev/null +++ b/sources/c/main/common/define.c @@ -0,0 +1,9 @@ +#include "../firewall.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/main/common/define.h b/sources/c/main/common/define.h new file mode 100644 index 0000000..7cc6dd1 --- /dev/null +++ b/sources/c/main/common/define.h @@ -0,0 +1,132 @@ +/** + * FLL - Level 3 + * + * Project: Firewall + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Provides the common define types. + * + * This is auto-included and should not need to be explicitly included. + */ +#ifndef _firewall_common_define_h +#define _firewall_common_define_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * The program allocation defines. + * + * firewall_allocation_*_d: + * - console: An allocation step used for small buffers specifically for console parameter. + * - large: An allocation step used for buffers that are anticipated to have large buffers. + * - pipe: A buffer size used for processing piped data. + * - small: An allocation step used for buffers that are anticipated to have small buffers. + */ +#ifndef _di_firewall_allocation_d_ + #define firewall_allocation_console_d 4 + #define firewall_allocation_large_d 256 + #define firewall_allocation_pipe_d 16384 + #define firewall_allocation_small_d 16 +#endif // _di_firewall_allocation_d_ + +/** + * Flags representing the current state of the processed rule. + * + * firewall_data_is_*_d: + * - none: No flags set. + * - global: The current processed rule is global. + * - local: The current processed rule is lock. + * - main: The current processed rule is main. + * - stop: The current processed rule is stop. + * - stop_main_lock: Helper flag representing main, stop, and lock being set. + */ +#ifndef _di_firewall_data_is_d_ + #define firewall_data_is_none_d 0x0 + #define firewall_data_is_global_d 0x1 + #define firewall_data_is_lock_d 0x2 + #define firewall_data_is_main_d 0x4 + #define firewall_data_is_stop_d 0x8 + #define firewall_data_is_stop_main_lock_d 0xe +#endif // _di_firewall_data_is_d_ + +/** + * Flags passed to the main function or program. + * + * firewall_main_flag_*_d: + * - none: No flags set. + * - copyright: Print copyright. + * - help: Print help. + * - ipv4: Operate in IPv4 by default or enable ipv4 when calling "show" commands. + * - ipv6: Operate in IPv6 by default or enable ipv6 when calling "show" commands. + * - ipv46: A helper flag representing both ipv4 and ipv6 flag bits being set. + * - operation: A helper flag representing every operation flag bit being set. + * - operation_lock: Perform the lock operation. + * - operation_restart: Perform the restart operation. + * - operation_show: Perform the show operation. + * - operation_show_nat: For the show operation, show nat. + * - operation_show_mangle: For the show operation, show mangle. + * - operation_show_filter: For the show operation, show filter. + * - operation_show_filter_nat_mangle: A helper flag representing the show nat, show mangle, and short filter flags set. + * - operation_start: Perform the start operation. + * - operation_start_restart: A helper flag representing both the start and restart operation flag set. + * - operation_stop: Perform the stop operation. + * - operation_stop_restart: A helper flag representing both the stop and restart operation flag set. + * - operation_stop_restart_lock: A helper flag representing both the stop, restart, and lock operation flag set. + * - pipe: Use the input pipe. + * - version: Print version. + * - version_copyright_help: A helper flag representing version, copyright, and help flag bits being set. + */ +#ifndef _di_firewall_main_flag_d_ + #define firewall_main_flag_none_d 0x0 + #define firewall_main_flag_copyright_d 0x1 + #define firewall_main_flag_help_d 0x2 + #define firewall_main_flag_ipv4_d 0x4 + #define firewall_main_flag_ipv6_d 0x8 + #define firewall_main_flag_ipv46_d 0xc + #define firewall_main_flag_operation_d 0xff0 + #define firewall_main_flag_operation_lock_d 0x10 + #define firewall_main_flag_operation_restart_d 0x20 + #define firewall_main_flag_operation_show_d 0x40 + #define firewall_main_flag_operation_show_nat_d 0x80 + #define firewall_main_flag_operation_show_mangle_d 0x100 + #define firewall_main_flag_operation_show_filter_d 0x200 + #define firewall_main_flag_operation_show_filter_nat_mangle_d 0x380 + #define firewall_main_flag_operation_start_d 0x400 + #define firewall_main_flag_operation_start_restart_d 0x420 + #define firewall_main_flag_operation_stop_d 0x800 + #define firewall_main_flag_operation_stop_restart_d 0x820 + #define firewall_main_flag_operation_stop_restart_lock_d 0x830 + #define firewall_main_flag_pipe_d 0x1000 + #define firewall_main_flag_version_d 0x2000 + #define firewall_main_flag_version_copyright_help_d 0x2003 +#endif // _di_firewall_main_flag_d_ + +/** + * The program signal defines. + * + * firewall_signal_*_d: + * - check_failsafe: When using threads, how many consecutive failures to check signal before aborting (as a recursion failsafe). + */ +#ifndef _di_firewall_signal_d_ + #define firewall_signal_check_failsafe_d 20000 +#endif // _di_firewall_signal_d_ + +/** + * A macro wrapping the appropriate signal check function based on threaded/non-threaded support. + */ +#ifndef _di_firewall_signal_check_d_ + #ifdef _di_thread_support_ + #define macro_firewall_signal_check(program, state) fll_program_signal_check_loop(program, state) + #else + #define macro_firewall_signal_check(program, state) fll_program_signal_check_simple(program, state) + #endif // _di_thread_support_ +#endif // _di_firewall_signal_check_d_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _firewall_common_define_h diff --git a/sources/c/main/common/enumeration.c b/sources/c/main/common/enumeration.c new file mode 100644 index 0000000..9bcd373 --- /dev/null +++ b/sources/c/main/common/enumeration.c @@ -0,0 +1,9 @@ +#include "../firewall.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/main/common/enumeration.h b/sources/c/main/common/enumeration.h new file mode 100644 index 0000000..90e952e --- /dev/null +++ b/sources/c/main/common/enumeration.h @@ -0,0 +1,174 @@ +/** + * FLL - Level 3 + * + * Project: Firewall + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Provides the common enumeration types. + * + * This is auto-included and should not need to be explicitly included. + */ +#ifndef _firewall_common_enumeration_h +#define _firewall_common_enumeration_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * The firewall action. + * + * firewall_action_*_e: + * - none: The action is none. + * - append: The action is append. + * - insert: The action is insert. + * - policy: The action is policy. + */ +#ifndef _di_firewall_action_e_ + enum { + firewall_action_none_e, + firewall_action_append_e, + firewall_action_insert_e, + firewall_action_policy_e, + }; // enum +#endif // _di_firewall_action_e_ + +/** + * The firewall chain. + * + * firewall_chain_*_e: + * - none: The chain is none. + * - custom: The chain is custom. + * - forward: The chain is forward. + * - input: The chain is input. + * - output: The chain is output. + * - postrouting: The chain is postrouting. + * - prerouting: The chain is prerouting. + */ +#ifndef _di_firewall_action_e_ + enum { + firewall_chain_none_e, + firewall_chain_custom_e, + firewall_chain_forward_e, + firewall_chain_input_e, + firewall_chain_output_e, + firewall_chain_postrouting_e, + firewall_chain_prerouting_e, + }; // enum +#endif // _di_firewall_action_e_ + +/** + * Flags representing the existence of reserved sets. + * + * firewall_data_has_*_e: + * - none: No flags set. + * - local: The current processed rule is lock. + * - main: The current processed rule is main. + * - stop: The current processed rule is stop. + */ +#ifndef _di_firewall_data_has_e_ + enum { + firewall_data_has_none_e = 0x0, + firewall_data_has_lock_e = 0x1, + firewall_data_has_main_e = 0x2, + firewall_data_has_stop_e = 0x4, + }; // enum +#endif // _di_firewall_data_has_e_ + +/** + * The firewall direction. + * + * firewall_direction_*_e: + * - none: No direction. + * - input: The input direction. + * - output: The output direction. + */ +#ifndef _di_firewall_direction_e_ + enum { + firewall_direction_none_e = 0, + firewall_direction_input_e, + firewall_direction_output_e, + }; // enum +#endif // _di_firewall_direction_e_ + +/** + * The firewall tool (the program being used). + * + * firewall_tool_*_e: + * - none: No flags set. + * - ip46tables: Use both iptables and ip6tables tools. + * - ip6tables: Use the ip6tables tool. + * - ipset: Use the ipset tool. + * - iptables: Use the iptables tool. + */ +#ifndef _di_firewall_tool_e_ + enum { + firewall_tool_none_e = 0, + firewall_tool_ip46tables_e, + firewall_tool_ip6tables_e, + firewall_tool_iptables_e, + firewall_tool_ipset_e, + }; // enum +#endif // _di_firewall_tool_e_ + +/** + * The main program parameters. + */ +#ifndef _di_firewall_parameter_e_ + enum { + firewall_parameter_4_e = f_console_standard_parameter_last_e, + firewall_parameter_6_e, + firewall_parameter_operation_lock_e, + firewall_parameter_operation_restart_e, + firewall_parameter_operation_show_e, + firewall_parameter_operation_start_e, + firewall_parameter_operation_stop_e, + }; // enum + + #define firewall_console_parameter_t_initialize \ + { \ + macro_fll_program_console_parameter_standard_initialize, \ + \ + macro_f_console_parameter_t_initialize_4(firewall_short_4_s, 0, f_console_flag_normal_d), \ + macro_f_console_parameter_t_initialize_4(firewall_short_6_s, 0, f_console_flag_normal_d), \ + macro_f_console_parameter_t_initialize_6(firewall_operation_lock_s, 0, f_console_flag_simple_d), \ + macro_f_console_parameter_t_initialize_6(firewall_operation_restart_s, 0, f_console_flag_simple_d), \ + macro_f_console_parameter_t_initialize_6(firewall_operation_show_s, 0, f_console_flag_simple_d), \ + macro_f_console_parameter_t_initialize_6(firewall_operation_start_s, 0, f_console_flag_simple_d), \ + macro_f_console_parameter_t_initialize_6(firewall_operation_stop_s, 0, f_console_flag_simple_d), \ + } + + #define firewall_parameter_total_d (f_console_parameter_state_type_total_d + 7) +#endif // _di_firewall_parameter_e_ + +/** + * Flags for fine-tuned print control. + * + * firewall_print_flag_*_e: + * - none: No flags set. + * - debug: Stream is for debug printing. + * - error: Stream is for error printing. + * - in: Stream is a source file. + * - message: Stream is for message printing. + * - out: Stream is a destination file. + * - warning: Stream is for warning printing. + */ +#ifndef _di_firewall_print_flag_e_ + enum { + firewall_print_flag_none_e = 0x0, + firewall_print_flag_debug_e = 0x1, + firewall_print_flag_error_e = 0x2, + firewall_print_flag_file_e = 0x4, + firewall_print_flag_in_e = 0x8, + firewall_print_flag_out_e = 0x10, + firewall_print_flag_message_e = 0x20, + firewall_print_flag_warning_e = 0x40, + }; // enum +#endif // _di_firewall_print_flag_e_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _firewall_common_enumeration_h diff --git a/sources/c/main/common/string.c b/sources/c/main/common/string.c new file mode 100644 index 0000000..a390902 --- /dev/null +++ b/sources/c/main/common/string.c @@ -0,0 +1,125 @@ +#include "../firewall.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_firewall_program_version_s_ + const f_string_static_t firewall_program_version_s = macro_f_string_static_t_initialize_1(FIREWALL_program_version_s, 0, FIREWALL_program_version_s_length); +#endif // _di_firewall_program_version_s_ + +#ifndef _di_firewall_program_name_s_ + const f_string_static_t firewall_program_name_s = macro_f_string_static_t_initialize_1(FIREWALL_program_name_s, 0, FIREWALL_program_name_s_length); + const f_string_static_t firewall_program_name_long_s = macro_f_string_static_t_initialize_1(FIREWALL_program_name_long_s, 0, FIREWALL_program_name_long_s_length); +#endif // _di_firewall_program_name_s_ + +#ifndef _di_firewall_program_help_parameters_s_ + const f_string_static_t firewall_program_help_parameters_s = macro_f_string_static_t_initialize_1(FIREWALL_program_help_parameters_s, 0, FIREWALL_program_help_parameters_s_length); +#endif // _di_firewall_program_help_parameters_s_ + +#ifndef _di_firewall_program_parameters_s_ + const f_string_static_t firewall_short_4_s = macro_f_string_static_t_initialize_1(FIREWALL_short_4_s, 0, FIREWALL_short_4_s_length); + const f_string_static_t firewall_short_6_s = macro_f_string_static_t_initialize_1(FIREWALL_short_6_s, 0, FIREWALL_short_6_s_length); +#endif // _di_firewall_program_parameters_s_ + +#ifndef _di_firewall_s_ + const f_string_static_t firewall_action_s = macro_f_string_static_t_initialize_1(FIREWALL_action_s, 0, FIREWALL_action_s_length); + const f_string_static_t firewall_action_append_s = macro_f_string_static_t_initialize_1(FIREWALL_action_append_s, 0, FIREWALL_action_append_s_length); + const f_string_static_t firewall_action_insert_s = macro_f_string_static_t_initialize_1(FIREWALL_action_insert_s, 0, FIREWALL_action_insert_s_length); + const f_string_static_t firewall_action_policy_s = macro_f_string_static_t_initialize_1(FIREWALL_action_policy_s, 0, FIREWALL_action_policy_s_length); + const f_string_static_t firewall_action_none_s = macro_f_string_static_t_initialize_1(FIREWALL_action_none_s, 0, FIREWALL_action_none_s_length); + + const f_string_static_t firewall_action_append_operation_s = macro_f_string_static_t_initialize_1(FIREWALL_action_append_operation_s, 0, FIREWALL_action_append_operation_s_length); + const f_string_static_t firewall_action_insert_operation_s = macro_f_string_static_t_initialize_1(FIREWALL_action_insert_operation_s, 0, FIREWALL_action_insert_operation_s_length); + const f_string_static_t firewall_action_policy_operation_s = macro_f_string_static_t_initialize_1(FIREWALL_action_policy_operation_s, 0, FIREWALL_action_policy_operation_s_length); + + const f_string_static_t firewall_chain_s = macro_f_string_static_t_initialize_1(FIREWALL_chain_s, 0, FIREWALL_chain_s_length); + const f_string_static_t firewall_chain_forward_s = macro_f_string_static_t_initialize_1(FIREWALL_chain_forward_s, 0, FIREWALL_chain_forward_s_length); + const f_string_static_t firewall_chain_drop_s = macro_f_string_static_t_initialize_1(FIREWALL_chain_drop_s, 0, FIREWALL_chain_drop_s_length); + const f_string_static_t firewall_chain_input_s = macro_f_string_static_t_initialize_1(FIREWALL_chain_input_s, 0, FIREWALL_chain_input_s_length); + const f_string_static_t firewall_chain_none_s = macro_f_string_static_t_initialize_1(FIREWALL_chain_none_s, 0, FIREWALL_chain_none_s_length); + const f_string_static_t firewall_chain_output_s = macro_f_string_static_t_initialize_1(FIREWALL_chain_output_s, 0, FIREWALL_chain_output_s_length); + const f_string_static_t firewall_chain_postrouting_s = macro_f_string_static_t_initialize_1(FIREWALL_chain_postrouting_s, 0, FIREWALL_chain_postrouting_s_length); + const f_string_static_t firewall_chain_prerouting_s = macro_f_string_static_t_initialize_1(FIREWALL_chain_prerouting_s, 0, FIREWALL_chain_prerouting_s_length); + + const f_string_static_t firewall_chain_create_operation_s = macro_f_string_static_t_initialize_1(FIREWALL_chain_create_operation_s, 0, FIREWALL_chain_create_operation_s_length); + const f_string_static_t firewall_chain_delete_operation_s = macro_f_string_static_t_initialize_1(FIREWALL_chain_delete_operation_s, 0, FIREWALL_chain_delete_operation_s_length); + const f_string_static_t firewall_chain_flush_operation_s = macro_f_string_static_t_initialize_1(FIREWALL_chain_flush_operation_s, 0, FIREWALL_chain_flush_operation_s_length); + + const f_string_static_t firewall_operation_start_s = macro_f_string_static_t_initialize_1(FIREWALL_operation_start_s, 0, FIREWALL_operation_start_s_length); + const f_string_static_t firewall_operation_stop_s = macro_f_string_static_t_initialize_1(FIREWALL_operation_stop_s, 0, FIREWALL_operation_stop_s_length); + const f_string_static_t firewall_operation_restart_s = macro_f_string_static_t_initialize_1(FIREWALL_operation_restart_s, 0, FIREWALL_operation_restart_s_length); + const f_string_static_t firewall_operation_lock_s = macro_f_string_static_t_initialize_1(FIREWALL_operation_lock_s, 0, FIREWALL_operation_lock_s_length); + const f_string_static_t firewall_operation_show_s = macro_f_string_static_t_initialize_1(FIREWALL_operation_show_s, 0, FIREWALL_operation_show_s_length); + + const f_string_static_t firewall_device_s = macro_f_string_static_t_initialize_1(FIREWALL_device_s, 0, FIREWALL_device_s_length); + const f_string_static_t firewall_device_all_s = macro_f_string_static_t_initialize_1(FIREWALL_device_all_s, 0, FIREWALL_device_all_s_length); + const f_string_static_t firewall_device_this_s = macro_f_string_static_t_initialize_1(FIREWALL_device_this_s, 0, FIREWALL_device_this_s_length); + const f_string_static_t firewall_device_loop_s = macro_f_string_static_t_initialize_1(FIREWALL_device_loop_s, 0, FIREWALL_device_loop_s_length); + + const f_string_static_t firewall_device_input_operation_s = macro_f_string_static_t_initialize_1(FIREWALL_device_input_operation_s, 0, FIREWALL_device_input_operation_s_length); + const f_string_static_t firewall_device_output_operation_s = macro_f_string_static_t_initialize_1(FIREWALL_device_output_operation_s, 0, FIREWALL_device_output_operation_s_length); + + const f_string_static_t firewall_direction_s = macro_f_string_static_t_initialize_1(FIREWALL_direction_s, 0, FIREWALL_direction_s_length); + const f_string_static_t firewall_direction_input_s = macro_f_string_static_t_initialize_1(FIREWALL_direction_input_s, 0, FIREWALL_direction_input_s_length); + const f_string_static_t firewall_direction_output_s = macro_f_string_static_t_initialize_1(FIREWALL_direction_output_s, 0, FIREWALL_direction_output_s_length); + const f_string_static_t firewall_direction_none_s = macro_f_string_static_t_initialize_1(FIREWALL_direction_none_s, 0, FIREWALL_direction_none_s_length); + + const f_string_static_t firewall_group_stop_s = macro_f_string_static_t_initialize_1(FIREWALL_group_stop_s, 0, FIREWALL_group_stop_s_length); + const f_string_static_t firewall_group_lock_s = macro_f_string_static_t_initialize_1(FIREWALL_group_lock_s, 0, FIREWALL_group_lock_s_length); + const f_string_static_t firewall_group_main_s = macro_f_string_static_t_initialize_1(FIREWALL_group_main_s, 0, FIREWALL_group_main_s_length); + + const f_string_static_t firewall_ip_list = macro_f_string_static_t_initialize_1(FIREWALL_ip_list_s, 0, FIREWALL_ip_list_s_length); + const f_string_static_t firewall_ip_list_source_s = macro_f_string_static_t_initialize_1(FIREWALL_ip_list_source_s, 0, FIREWALL_ip_list_source_s_length); + const f_string_static_t firewall_ip_list_source_action_s = macro_f_string_static_t_initialize_1(FIREWALL_ip_list_source_action_s, 0, FIREWALL_ip_list_source_action_s_length); + const f_string_static_t firewall_ip_list_destination_s = macro_f_string_static_t_initialize_1(FIREWALL_ip_list_destination_s, 0, FIREWALL_ip_list_destination_s_length); + const f_string_static_t firewall_ip_list_destination_action_s = macro_f_string_static_t_initialize_1(FIREWALL_ip_list_destination_action_s, 0, FIREWALL_ip_list_destination_action_s_length); + + const f_string_static_t firewall_protocol_s = macro_f_string_static_t_initialize_1(FIREWALL_protocol_s, 0, FIREWALL_protocol_s_length); + const f_string_static_t firewall_protocol_operation_s = macro_f_string_static_t_initialize_1(FIREWALL_protocol_operation_s, 0, FIREWALL_protocol_operation_s_length); + const f_string_static_t firewall_protocol_none_s = macro_f_string_static_t_initialize_1(FIREWALL_protocol_none_s, 0, FIREWALL_protocol_none_s_length); + + const f_string_static_t firewall_rule_s = macro_f_string_static_t_initialize_1(FIREWALL_rule_s, 0, FIREWALL_rule_s_length); + + const f_string_static_t firewall_show_filter_s = macro_f_string_static_t_initialize_1(FIREWALL_show_filter_s, 0, FIREWALL_show_filter_s_length); + const f_string_static_t firewall_show_mangle_s = macro_f_string_static_t_initialize_1(FIREWALL_show_mangle_s, 0, FIREWALL_show_mangle_s_length); + const f_string_static_t firewall_show_nat_s = macro_f_string_static_t_initialize_1(FIREWALL_show_nat_s, 0, FIREWALL_show_nat_s_length); + + const f_string_static_t firewall_show_parameter_exact_s = macro_f_string_static_t_initialize_1(FIREWALL_show_parameter_exact_s, 0, FIREWALL_show_parameter_exact_s_length); + const f_string_static_t firewall_show_parameter_verbose_s = macro_f_string_static_t_initialize_1(FIREWALL_show_parameter_verbose_s, 0, FIREWALL_show_parameter_verbose_s_length); + const f_string_static_t firewall_show_parameter_table_s = macro_f_string_static_t_initialize_1(FIREWALL_show_parameter_table_s, 0, FIREWALL_show_parameter_table_s_length); + const f_string_static_t firewall_show_parameter_numeric_s = macro_f_string_static_t_initialize_1(FIREWALL_show_parameter_numeric_s, 0, FIREWALL_show_parameter_numeric_s_length); + const f_string_static_t firewall_show_parameter_list_s = macro_f_string_static_t_initialize_1(FIREWALL_show_parameter_list_s, 0, FIREWALL_show_parameter_list_s_length); + + const f_string_static_t firewall_tool_s = macro_f_string_static_t_initialize_1(FIREWALL_tool_s, 0, FIREWALL_tool_s_length); + const f_string_static_t firewall_tool_iptables_s = macro_f_string_static_t_initialize_1(FIREWALL_tool_iptables_s, 0, FIREWALL_tool_iptables_s_length); + const f_string_static_t firewall_tool_ip6tables_s = macro_f_string_static_t_initialize_1(FIREWALL_tool_ip6tables_s, 0, FIREWALL_tool_ip6tables_s_length); + const f_string_static_t firewall_tool_ip46tables_s = macro_f_string_static_t_initialize_1(FIREWALL_tool_ip46tables_s, 0, FIREWALL_tool_ip46tables_s_length); + const f_string_static_t firewall_tool_ipset_s = macro_f_string_static_t_initialize_1(FIREWALL_tool_ipset_s, 0, FIREWALL_tool_ipset_s_length); +#endif // _di_firewall_s_ + +#ifndef _di_firewall_path_s_ + const f_string_static_t firewall_file_first_s = macro_f_string_static_t_initialize_1(FIREWALL_file_first_s, 0, FIREWALL_file_first_s_length); + const f_string_static_t firewall_file_last_s = macro_f_string_static_t_initialize_1(FIREWALL_file_last_s, 0, FIREWALL_file_last_s_length); + const f_string_static_t firewall_file_other_s = macro_f_string_static_t_initialize_1(FIREWALL_file_other_s, 0, FIREWALL_file_other_s_length); + const f_string_static_t firewall_file_suffix_s = macro_f_string_static_t_initialize_1(FIREWALL_file_suffix_s, 0, FIREWALL_file_suffix_s_length); + + const f_string_static_t firewall_network_firewall_path_s = macro_f_string_static_t_initialize_1(FIREWALL_network_firewall_path_s, 0, FIREWALL_network_firewall_path_s_length); + const f_string_static_t firewall_network_devices_s = macro_f_string_static_t_initialize_1(FIREWALL_network_devices_s, 0, FIREWALL_network_devices_s_length); +#endif // _di_firewall_path_s_ + +#ifndef _di_firewall_print_show_s_ + const f_string_static_t firewall_print_show_filter_s = macro_f_string_static_t_initialize_1(FIREWALL_print_show_filter_s, 0, FIREWALL_print_show_filter_s_length); + const f_string_static_t firewall_print_show_ipv4_s = macro_f_string_static_t_initialize_1(FIREWALL_print_show_ipv4_s, 0, FIREWALL_print_show_ipv4_s_length); + const f_string_static_t firewall_print_show_ipv6_s = macro_f_string_static_t_initialize_1(FIREWALL_print_show_ipv6_s, 0, FIREWALL_print_show_ipv6_s_length); + const f_string_static_t firewall_print_show_mangle_s = macro_f_string_static_t_initialize_1(FIREWALL_print_show_mangle_s, 0, FIREWALL_print_show_mangle_s_length); + const f_string_static_t firewall_print_show_nat_s = macro_f_string_static_t_initialize_1(FIREWALL_print_show_nat_s, 0, FIREWALL_print_show_nat_s_length); + + const f_string_static_t firewall_print_show_bars_26_s = macro_f_string_static_t_initialize_1(FIREWALL_print_show_bars_26_s, 0, FIREWALL_print_show_bars_26_s_length); + const f_string_static_t firewall_print_show_bars_27_s = macro_f_string_static_t_initialize_1(FIREWALL_print_show_bars_27_s, 0, FIREWALL_print_show_bars_27_s_length); + const f_string_static_t firewall_print_show_bars_28_s = macro_f_string_static_t_initialize_1(FIREWALL_print_show_bars_28_s, 0, FIREWALL_print_show_bars_28_s_length); +#endif // _di_firewall_print_show_s_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/main/common/string.h b/sources/c/main/common/string.h new file mode 100644 index 0000000..d5352b1 --- /dev/null +++ b/sources/c/main/common/string.h @@ -0,0 +1,404 @@ +/** + * FLL - Level 3 + * + * Project: Firewall + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Provides the common string structures. + * + * This is auto-included and should not need to be explicitly included. + */ +#ifndef _firewall_common_string_h +#define _firewall_common_string_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * The program version. + */ +#ifndef _di_firewall_program_version_s_ + #define FIREWALL_program_version_major_s F_string_ascii_0_s + #define FIREWALL_program_version_minor_s F_string_ascii_7_s + #define FIREWALL_program_version_micro_s F_string_ascii_3_s + + #define FIREWALL_program_version_major_s_length F_string_ascii_0_s_length + #define FIREWALL_program_version_minor_s_length F_string_ascii_7_s_length + #define FIREWALL_program_version_micro_s_length F_string_ascii_3_s_length + + #if !(defined(FIREWALL_program_version_nano_prefix_s) && defined(FIREWALL_program_version_nano_prefix_s_length)) + #define FIREWALL_program_version_nano_prefix_s + #define FIREWALL_program_version_nano_prefix_s_length 0 + #endif // !(defined(FIREWALL_program_version_nano_prefix_s) && defined(FIREWALL_program_version_nano_prefix_s_length)) + + #if !(defined(FIREWALL_program_version_nano_s) && defined(FIREWALL_program_version_nano_s_length)) + #define FIREWALL_program_version_nano_s + #define FIREWALL_program_version_nano_s_length 0 + #endif // !(defined(FIREWALL_program_version_nano_s) && defined(FIREWALL_program_version_nano_s_length)) + + #define FIREWALL_program_version_s FIREWALL_program_version_major_s F_string_ascii_period_s FIREWALL_program_version_minor_s F_string_ascii_period_s FIREWALL_program_version_micro_s FIREWALL_program_version_nano_prefix_s FIREWALL_program_version_nano_s + + #define FIREWALL_program_version_s_length FIREWALL_program_version_major_s_length + F_string_ascii_period_s_length + FIREWALL_program_version_minor_s_length + F_string_ascii_period_s_length + FIREWALL_program_version_micro_s_length + FIREWALL_program_version_nano_prefix_s_length + FIREWALL_program_version_nano_s_length + + extern const f_string_static_t firewall_program_version_s; +#endif // _di_firewall_program_version_s_ + +/** + * The program name. + */ +#ifndef _di_firewall_program_name_s_ + #define FIREWALL_program_name_s "firewall" + #define FIREWALL_program_name_long_s "Kevux Firewall Manager" + + #define FIREWALL_program_name_s_length 8 + #define FIREWALL_program_name_long_s_length 22 + + extern const f_string_static_t firewall_program_name_s; + extern const f_string_static_t firewall_program_name_long_s; +#endif // _di_firewall_program_name_s_ + +/** + * The program help related data. + */ +#ifndef _di_firewall_program_help_parameters_s_ + #define FIREWALL_program_help_parameters_s "operation" + #define FIREWALL_program_help_parameters_s_length 9 + + extern const f_string_static_t firewall_program_help_parameters_s; +#endif // _di_firewall_program_help_parameters_s_ + +/** + * The main program parameters. + */ +#ifndef _di_firewall_parameter_s_ + #define FIREWALL_short_4_s "4" + #define FIREWALL_short_6_s "6" + + #define FIREWALL_short_4_s_length 1 + #define FIREWALL_short_6_s_length 1 + + extern const f_string_static_t firewall_short_4_s; + extern const f_string_static_t firewall_short_6_s; +#endif // _di_firewall_parameter_s_ + +/** + * The firewall strings. + */ +#ifndef _di_firewall_s_ + #define FIREWALL_action_s "action" + #define FIREWALL_action_append_s "append" + #define FIREWALL_action_insert_s "insert" + #define FIREWALL_action_policy_s "policy" + #define FIREWALL_action_none_s "none" + + #define FIREWALL_action_append_operation_s "-A" + #define FIREWALL_action_insert_operation_s "-I" + #define FIREWALL_action_policy_operation_s "-P" + + #define FIREWALL_chain_s "chain" + #define FIREWALL_chain_forward_s "FORWARD" + #define FIREWALL_chain_drop_s "DROP" + #define FIREWALL_chain_input_s "INPUT" + #define FIREWALL_chain_none_s "none" + #define FIREWALL_chain_output_s "OUTPUT" + #define FIREWALL_chain_postrouting_s "POSTROUTING" + #define FIREWALL_chain_prerouting_s "PREROUTING" + + #define FIREWALL_chain_create_operation_s "-N" + #define FIREWALL_chain_delete_operation_s "-X" + #define FIREWALL_chain_flush_operation_s "-F" + + #define FIREWALL_operation_start_s "start" + #define FIREWALL_operation_stop_s "stop" + #define FIREWALL_operation_restart_s "restart" + #define FIREWALL_operation_lock_s "lock" + #define FIREWALL_operation_show_s "show" + + #define FIREWALL_device_s "device" + #define FIREWALL_device_all_s "all" + #define FIREWALL_device_this_s "this" + #define FIREWALL_device_loop_s "lo" + + #define FIREWALL_device_input_operation_s "-i" + #define FIREWALL_device_output_operation_s "-o" + + #define FIREWALL_direction_s "direction" + #define FIREWALL_direction_input_s "input" + #define FIREWALL_direction_output_s "output" + #define FIREWALL_direction_none_s "none" + + #define FIREWALL_group_stop_s "stop" + #define FIREWALL_group_lock_s "lock" + #define FIREWALL_group_main_s "main" + + #define FIREWALL_ip_list_s "ip_list" + #define FIREWALL_ip_list_source_s "source" + #define FIREWALL_ip_list_source_action_s "-s" + #define FIREWALL_ip_list_destination_s "destination" + #define FIREWALL_ip_list_destination_action_s "-d" + + #define FIREWALL_protocol_s "protocol" + #define FIREWALL_protocol_operation_s "-p" + #define FIREWALL_protocol_none_s "none" + + #define FIREWALL_rule_s "rule" + + #define FIREWALL_show_filter_s "filter" + #define FIREWALL_show_mangle_s "mangle" + #define FIREWALL_show_nat_s "nat" + + #define FIREWALL_show_parameter_exact_s "-x" + #define FIREWALL_show_parameter_verbose_s "-v" + #define FIREWALL_show_parameter_table_s "-t" + #define FIREWALL_show_parameter_numeric_s "--numeric" + #define FIREWALL_show_parameter_list_s "--list" + + #define FIREWALL_tool_s "tool" + #define FIREWALL_tool_iptables_s "iptables" + #define FIREWALL_tool_ip6tables_s "ip6tables" + #define FIREWALL_tool_ip46tables_s "ip46tables" + #define FIREWALL_tool_ipset_s "ipset" + + #define FIREWALL_action_s_length 6 + #define FIREWALL_action_append_s_length 6 + #define FIREWALL_action_insert_s_length 6 + #define FIREWALL_action_policy_s_length 6 + #define FIREWALL_action_none_s_length 4 + + #define FIREWALL_action_append_operation_s_length 2 + #define FIREWALL_action_insert_operation_s_length 2 + #define FIREWALL_action_policy_operation_s_length 2 + + #define FIREWALL_chain_s_length 5 + #define FIREWALL_chain_forward_s_length 7 + #define FIREWALL_chain_drop_s_length 4 + #define FIREWALL_chain_input_s_length 5 + #define FIREWALL_chain_none_s_length 4 + #define FIREWALL_chain_output_s_length 6 + #define FIREWALL_chain_postrouting_s_length 12 + #define FIREWALL_chain_prerouting_s_length 11 + + #define FIREWALL_chain_create_operation_s_length 2 + #define FIREWALL_chain_delete_operation_s_length 2 + #define FIREWALL_chain_flush_operation_s_length 2 + + #define FIREWALL_operation_start_s_length 5 + #define FIREWALL_operation_stop_s_length 4 + #define FIREWALL_operation_restart_s_length 7 + #define FIREWALL_operation_lock_s_length 4 + #define FIREWALL_operation_show_s_length 4 + + #define FIREWALL_device_s_length 6 + #define FIREWALL_device_all_s_length 3 + #define FIREWALL_device_this_s_length 4 + #define FIREWALL_device_loop_s_length 2 + + #define FIREWALL_device_input_operation_s_length 2 + #define FIREWALL_device_output_operation_s_length 2 + + #define FIREWALL_direction_s_length 9 + #define FIREWALL_direction_input_s_length 5 + #define FIREWALL_direction_output_s_length 6 + #define FIREWALL_direction_none_s_length 4 + + #define FIREWALL_group_stop_s_length 4 + #define FIREWALL_group_lock_s_length 4 + #define FIREWALL_group_main_s_length 4 + + #define FIREWALL_ip_list_s_length 7 + #define FIREWALL_ip_list_source_s_length 6 + #define FIREWALL_ip_list_source_action_s_length 2 + #define FIREWALL_ip_list_destination_s_length 11 + #define FIREWALL_ip_list_destination_action_s_length 2 + + #define FIREWALL_protocol_s_length 8 + #define FIREWALL_protocol_operation_s_length 2 + #define FIREWALL_protocol_none_s_length 4 + + #define FIREWALL_rule_s_length 4 + + #define FIREWALL_show_filter_s_length 6 + #define FIREWALL_show_mangle_s_length 6 + #define FIREWALL_show_nat_s_length 3 + + #define FIREWALL_show_parameter_exact_s_length 2 + #define FIREWALL_show_parameter_verbose_s_length 2 + #define FIREWALL_show_parameter_table_s_length 2 + #define FIREWALL_show_parameter_numeric_s_length 9 + #define FIREWALL_show_parameter_list_s_length 6 + + #define FIREWALL_tool_s_length 4 + #define FIREWALL_tool_iptables_s_length 8 + #define FIREWALL_tool_ip6tables_s_length 9 + #define FIREWALL_tool_ip46tables_s_length 10 + #define FIREWALL_tool_ipset_s_length 5 + + extern const f_string_static_t firewall_action_s; + extern const f_string_static_t firewall_action_append_s; + extern const f_string_static_t firewall_action_insert_s; + extern const f_string_static_t firewall_action_policy_s; + extern const f_string_static_t firewall_action_none_s; + + extern const f_string_static_t firewall_action_append_operation_s; + extern const f_string_static_t firewall_action_insert_operation_s; + extern const f_string_static_t firewall_action_policy_operation_s; + + extern const f_string_static_t firewall_chain_s; + extern const f_string_static_t firewall_chain_forward_s; + extern const f_string_static_t firewall_chain_drop_s; + extern const f_string_static_t firewall_chain_input_s; + extern const f_string_static_t firewall_chain_none_s; + extern const f_string_static_t firewall_chain_output_s; + extern const f_string_static_t firewall_chain_postrouting_s; + extern const f_string_static_t firewall_chain_prerouting_s; + + extern const f_string_static_t firewall_chain_create_operation_s; + extern const f_string_static_t firewall_chain_delete_operation_s; + extern const f_string_static_t firewall_chain_flush_operation_s; + + extern const f_string_static_t firewall_operation_start_s; + extern const f_string_static_t firewall_operation_stop_s; + extern const f_string_static_t firewall_operation_restart_s; + extern const f_string_static_t firewall_operation_lock_s; + extern const f_string_static_t firewall_operation_show_s; + + extern const f_string_static_t firewall_device_s; + extern const f_string_static_t firewall_device_all_s; + extern const f_string_static_t firewall_device_this_s; + extern const f_string_static_t firewall_device_loop_s; + + extern const f_string_static_t firewall_device_input_operation_s; + extern const f_string_static_t firewall_device_output_operation_s; + + extern const f_string_static_t firewall_direction_s; + extern const f_string_static_t firewall_direction_input_s; + extern const f_string_static_t firewall_direction_output_s; + extern const f_string_static_t firewall_direction_none_s; + + extern const f_string_static_t firewall_group_stop_s; + extern const f_string_static_t firewall_group_lock_s; + extern const f_string_static_t firewall_group_main_s; + + extern const f_string_static_t firewall_ip_list; + extern const f_string_static_t firewall_ip_list_source_s; + extern const f_string_static_t firewall_ip_list_source_action_s; + extern const f_string_static_t firewall_ip_list_destination_s; + extern const f_string_static_t firewall_ip_list_destination_action_s; + + extern const f_string_static_t firewall_protocol_s; + extern const f_string_static_t firewall_protocol_operation_s; + extern const f_string_static_t firewall_protocol_none_s; + + extern const f_string_static_t firewall_rule_s; + + extern const f_string_static_t firewall_show_filter_s; + extern const f_string_static_t firewall_show_mangle_s; + extern const f_string_static_t firewall_show_nat_s; + + extern const f_string_static_t firewall_show_parameter_exact_s; + extern const f_string_static_t firewall_show_parameter_verbose_s; + extern const f_string_static_t firewall_show_parameter_table_s; + extern const f_string_static_t firewall_show_parameter_numeric_s; + extern const f_string_static_t firewall_show_parameter_list_s; + + extern const f_string_static_t firewall_tool_s; + extern const f_string_static_t firewall_tool_iptables_s; + extern const f_string_static_t firewall_tool_ip6tables_s; + extern const f_string_static_t firewall_tool_ip46tables_s; + extern const f_string_static_t firewall_tool_ipset_s; +#endif // _di_firewall_s_ + +/** + * The main program operations. + */ +#ifndef _di_firewall_operation_s_ + #define FIREWALL_operation_start_s "start" + #define FIREWALL_operation_stop_s "stop" + #define FIREWALL_operation_restart_s "restart" + #define FIREWALL_operation_lock_s "lock" + #define FIREWALL_operation_show_s "show" + + #define FIREWALL_operation_start_s_length 5 + #define FIREWALL_operation_stop_s_length 4 + #define FIREWALL_operation_restart_s_length 7 + #define FIREWALL_operation_lock_s_length 4 + #define FIREWALL_operation_show_s_length 4 + + extern const f_string_static_t firewall_operation_start_s; + extern const f_string_static_t firewall_operation_stop_s; + extern const f_string_static_t firewall_operation_restart_s; + extern const f_string_static_t firewall_operation_lock_s; + extern const f_string_static_t firewall_operation_show_s; +#endif // _di_firewall_operation_s_ + +/** + * The program paths. + */ +#ifndef _di_firewall_path_s_ + #define FIREWALL_file_first_s "firewall-first" + #define FIREWALL_file_last_s "firewall-last" + #define FIREWALL_file_other_s "firewall-other" + #define FIREWALL_file_suffix_s "-firewall" + + #define FIREWALL_network_firewall_path_s "/etc/network/firewall/" + #define FIREWALL_network_devices_s "/sys/class/net/" + + #define FIREWALL_file_first_s_length 14 + #define FIREWALL_file_last_s_length 13 + #define FIREWALL_file_other_s_length 14 + #define FIREWALL_file_suffix_s_length 9 + + #define FIREWALL_network_firewall_path_s_length 22 + #define FIREWALL_network_devices_s_length 15 + + extern const f_string_static_t firewall_file_first_s; + extern const f_string_static_t firewall_file_last_s; + extern const f_string_static_t firewall_file_other_s; + extern const f_string_static_t firewall_file_suffix_s; + + extern const f_string_static_t firewall_network_firewall_path_s; + extern const f_string_static_t firewall_network_devices_s; +#endif // _di_firewall_path_s_ + +/** + * The show option related strings for printing to the screen. + */ +#ifndef _di_firewall_print_show_s_ + #define FIREWALL_print_show_filter_s "FILTER" + #define FIREWALL_print_show_ipv4_s "IPv4" + #define FIREWALL_print_show_ipv6_s "IPv6" + #define FIREWALL_print_show_mangle_s "MANGLE" + #define FIREWALL_print_show_nat_s "NAT" + + #define FIREWALL_print_show_bars_26_s "==========================" + #define FIREWALL_print_show_bars_27_s "============================" + #define FIREWALL_print_show_bars_28_s "============================" + + #define FIREWALL_print_show_filter_s_length 6 + #define FIREWALL_print_show_ipv4_s_length 4 + #define FIREWALL_print_show_ipv6_s_length 4 + #define FIREWALL_print_show_mangle_s_length 6 + #define FIREWALL_print_show_nat_s_length 3 + + #define FIREWALL_print_show_bars_26_s_length 26 + #define FIREWALL_print_show_bars_27_s_length 27 + #define FIREWALL_print_show_bars_28_s_length 28 + + extern const f_string_static_t firewall_print_show_filter_s; + extern const f_string_static_t firewall_print_show_ipv4_s; + extern const f_string_static_t firewall_print_show_ipv6_s; + extern const f_string_static_t firewall_print_show_mangle_s; + extern const f_string_static_t firewall_print_show_nat_s; + + extern const f_string_static_t firewall_print_show_bars_26_s; + extern const f_string_static_t firewall_print_show_bars_27_s; + extern const f_string_static_t firewall_print_show_bars_28_s; +#endif // _di_firewall_print_show_s_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _firewall_common_string_h diff --git a/sources/c/main/common/type.c b/sources/c/main/common/type.c new file mode 100644 index 0000000..2587146 --- /dev/null +++ b/sources/c/main/common/type.c @@ -0,0 +1,73 @@ +#include "../firewall.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_firewall_cache_delete_ + void firewall_cache_delete(firewall_cache_t * const cache) { + + if (!cache) return; + + f_file_close(&cache->file); + + f_memory_array_resize(0, sizeof(f_char_t), (void **) &cache->buffer.string, &cache->buffer.used, &cache->buffer.size); + f_memory_array_resize(0, sizeof(f_char_t), (void **) &cache->device.string, &cache->device.used, &cache->device.size); + f_memory_array_resize(0, sizeof(f_char_t), (void **) &cache->ip_list.string, &cache->ip_list.used, &cache->ip_list.size); + f_memory_array_resize(0, sizeof(f_char_t), (void **) &cache->path_file.string, &cache->path_file.used, &cache->path_file.size); + f_memory_array_resize(0, sizeof(f_char_t), (void **) &cache->path_file_specific.string, &cache->path_file_specific.used, &cache->path_file_specific.size); + f_memory_array_resize(0, sizeof(f_char_t), (void **) &cache->protocol.string, &cache->protocol.used, &cache->protocol.size); + + f_memory_arrays_resize(0, sizeof(f_string_dynamic_t), (void **) &cache->arguments.array, &cache->arguments.used, &cache->arguments.size, &f_string_dynamics_delete_callback); + + f_memory_array_resize(0, sizeof(f_number_unsigned_t), (void **) &cache->delimits.array, &cache->delimits.used, &cache->delimits.size); + + f_memory_array_resize(0, sizeof(f_range_t), (void **) &cache->basic_objects.array, &cache->basic_objects.used, &cache->basic_objects.size); + f_memory_arrays_resize(0, sizeof(f_ranges_t), (void **) &cache->basic_contents.array, &cache->basic_contents.used, &cache->basic_contents.size, &f_rangess_delete_callback); + } +#endif // _di_firewall_cache_delete_ + +#ifndef _di_firewall_data_delete_ + void firewall_data_delete(firewall_data_t * const data) { + + if (!data) return; + + f_memory_array_resize(0, sizeof(f_char_t), (void **) &data->buffer.string, &data->buffer.used, &data->buffer.size); + + f_memory_array_resize(0, sizeof(f_number_unsigned_t), (void **) &data->chain_ids.array, &data->chain_ids.used, &data->chain_ids.size); + + f_memory_array_resize(0, sizeof(f_range_t), (void **) &data->comments.array, &data->comments.used, &data->comments.size); + f_memory_array_resize(0, sizeof(f_range_t), (void **) &data->chain_objects.array, &data->chain_objects.used, &data->chain_objects.size); + f_memory_array_resize(0, sizeof(f_range_t), (void **) &data->rule_objects.array, &data->rule_objects.used, &data->rule_objects.size); + + f_memory_arrays_resize(0, sizeof(f_ranges_t), (void **) &data->chain_contents.array, &data->chain_contents.used, &data->chain_contents.size, &f_rangess_delete_callback); + f_memory_arrays_resize(0, sizeof(f_ranges_t), (void **) &data->rule_contents.array, &data->rule_contents.used, &data->rule_contents.size, &f_rangess_delete_callback); + } +#endif // _di_firewall_data_delete_ + +#ifndef _di_firewall_main_delete_ + void firewall_main_delete(firewall_main_t * const main) { + + if (!main) return; + + fll_program_data_delete(&main->program); + + firewall_setting_delete(&main->setting); + firewall_data_delete(&main->data); + firewall_cache_delete(&main->cache); + } +#endif // _di_firewall_main_delete_ + +#ifndef _di_firewall_setting_delete_ + void firewall_setting_delete(firewall_setting_t * const setting) { + + if (!setting) return; + + f_memory_arrays_resize(0, sizeof(f_string_dynamic_t), (void **) &setting->chains.array, &setting->chains.used, &setting->chains.size, &f_string_dynamics_delete_callback); + f_memory_arrays_resize(0, sizeof(f_string_dynamic_t), (void **) &setting->devices.array, &setting->devices.used, &setting->devices.size, &f_string_dynamics_delete_callback); + } +#endif // _di_firewall_setting_delete_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/main/common/type.h b/sources/c/main/common/type.h new file mode 100644 index 0000000..926c78b --- /dev/null +++ b/sources/c/main/common/type.h @@ -0,0 +1,279 @@ +/** + * FLL - Level 3 + * + * Project: Firewall + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Provides the common type structures. + * + * This is auto-included and should not need to be explicitly included. + */ +#ifndef _firewall_common_type_h +#define _firewall_common_type_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Pre-define the main type so it can be used in child classes. + */ +#ifndef _di_firewall_main_t_typedef_ + typedef struct firewall_main_t_ firewall_main_t; +#endif // _di_firewall_main_t_typedef_ + +/** + * A cache used for during processing. + * + * Properties: + * - file: The file structure. + * + * - buffer: A buffer used when proessing the basic objects and contents cache. + * - device: The device. + * - ip_list: The ip list. + * - path_file: The path to a file. + * - path_file_specific: The specific path to a file. + * - protocol: The protocol. + * - arguments: The arguments array. + * + * - delimits: The delimits array used when loading FSS data. + * + * - basic_objects: The FSS Basic Objects. + * - basic_contents: The FSS Basic Contents. + */ +#ifndef _di_firewall_cache_t_ + typedef struct { + f_file_t file; + + f_string_dynamic_t buffer; + f_string_dynamic_t device; + f_string_dynamic_t ip_list; + f_string_dynamic_t path_file; + f_string_dynamic_t path_file_specific; + f_string_dynamic_t protocol; + f_string_dynamics_t arguments; + + f_number_unsigneds_t delimits; + + f_ranges_t basic_objects; + f_rangess_t basic_contents; + } firewall_cache_t; + + #define firewall_cache_t_initialize \ + { \ + f_file_t_initialize, \ + f_string_dynamic_t_initialize, \ + f_string_dynamic_t_initialize, \ + f_string_dynamic_t_initialize, \ + f_string_dynamic_t_initialize, \ + f_string_dynamic_t_initialize, \ + f_string_dynamic_t_initialize, \ + f_string_dynamics_t_initialize, \ + f_number_unsigneds_t_initialize, \ + f_ranges_t_initialize, \ + f_rangess_t_initialize, \ + } +#endif // _di_firewall_cache_t_ + +/** + * A data used for building and processing firewall rules. + * + * Properties: + * - is: Flags used to represent the state in the current set being processed. + * - has: Flags used to represent if each at has a position. + * + * - chain: The chain currently being processed (fom chain_contents). + * - device: The device position. + * - lock: The lock position. + * - main: The main position. + * - stop: The stop position. + * - range: A range used during operation processing. + * + * - file: The file name currently in use. + * - buffer: The entire set of chains and rules to operate on. + * + * - chain_ids: The list of chain IDs. + * + * - chain_objects: The list of chain Objects. + * - rule_objects: The list of rule Objects. + * - chain_contents: The list of chain Contents. + * - rule_contents: The list of rule Contents. + */ +#ifndef _di_firewall_data_t_ + typedef struct { + uint8_t is; + uint8_t has; + + f_number_unsigned_t chain; + f_number_unsigned_t device; + f_number_unsigned_t lock; + f_number_unsigned_t main; + f_number_unsigned_t stop; + f_range_t range; + + f_string_static_t file; + f_string_dynamic_t buffer; + + f_number_unsigneds_t chain_ids; + + f_ranges_t comments; + f_ranges_t chain_objects; + f_ranges_t rule_objects; + f_rangess_t chain_contents; + f_rangess_t rule_contents; + } firewall_data_t; + + #define firewall_data_t_initialize \ + { \ + firewall_data_is_none_d, \ + firewall_data_has_none_e, \ + 0, \ + 0, \ + 0, \ + 0, \ + 0, \ + f_range_t_initialize, \ + f_string_static_t_initialize, \ + f_string_dynamic_t_initialize, \ + f_number_unsigneds_t_initialize, \ + f_ranges_t_initialize, \ + f_ranges_t_initialize, \ + f_ranges_t_initialize, \ + f_rangess_t_initialize, \ + f_rangess_t_initialize, \ + } +#endif // _di_firewall_data_t_ + +/** + * The firewall main program settings. + * + * This is passed to the program-specific main entry point to designate program settings. + * These program settings are often processed from the program arguments (often called the command line arguments). + * + * Properties: + * - flag: Flags passed to the main function. + * - state: The state information. + * + * - chains: An array of all chains. @todo probably should be moved into data. + * - devices: An array of all devices. @todo probably should be moved into data. + */ +#ifndef _di_firewall_setting_t_ + typedef struct { + uint16_t flag; + f_state_t state; + + f_string_dynamics_t chains; + f_string_dynamics_t devices; + } firewall_setting_t; + + #define firewall_setting_t_initialize \ + { \ + firewall_main_flag_none_d, \ + f_state_t_initialize, \ + f_string_dynamics_t_initialize, \ + f_string_dynamics_t_initialize, \ + } +#endif // _di_firewall_setting_t_ + +/** + * The main program data as a single structure. + * + * Properties: + * - program: The main program data. + * - setting: The settings data. + * - data: The firewall data. + * - cache: The firewall cache. + */ +#ifndef _di_firewall_main_t_ + struct firewall_main_t_ { + fll_program_data_t program; + firewall_setting_t setting; + firewall_data_t data; + firewall_cache_t cache; + }; + + #define firewall_main_t_initialize \ + { \ + fll_program_data_t_initialize, \ + firewall_setting_t_initialize, \ + firewall_data_t_initialize, \ + firewall_cache_t_initialize, \ + } +#endif // _di_firewall_main_t_ + +/** + * De-allocate firewall cache. + * + * @param cache + * The firewall cache. + * + * Must not be NULL. + * + * This does not alter main.setting.state.status. + * + * @see f_file_close() + * @see f_memory_array_resize() + * @see f_memory_arrays_resize() + */ +#ifndef _di_firewall_cache_delete_ + extern void firewall_cache_delete(firewall_cache_t * const cache); +#endif // _di_firewall_cache_delete_ + +/** + * De-allocate firewall data. + * + * @param data + * The firewall data. + * + * Must not be NULL. + * + * This does not alter main.setting.state.status. + * + * @see f_memory_array_resize() + * @see f_memory_arrays_resize() + */ +#ifndef _di_firewall_data_delete_ + extern void firewall_data_delete(firewall_data_t * const data); +#endif // _di_firewall_data_delete_ + +/** + * De-allocate main program data. + * + * @param main + * The main program data. + * + * Must not be NULL. + * + * This does not alter main.setting.state.status. + * + * @see fll_program_data_delete() + * @see firewall_cache_delete() + * @see firewall_data_delete() + * @see firewall_setting_delete() + */ +#ifndef _di_firewall_main_delete_ + extern void firewall_main_delete(firewall_main_t * const main); +#endif // _di_firewall_main_delete_ + +/** + * Delete the program main setting data. + * + * @param setting + * The program main setting data. + * + * Must not be NULL. + * + * This does not alter setting.state.status. + * + * @see f_memory_arrays_resize() + */ +#ifndef _di_firewall_setting_delete_ + extern void firewall_setting_delete(firewall_setting_t * const setting); +#endif // _di_firewall_setting_delete_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _firewall_common_type_h diff --git a/sources/c/main/firewall.c b/sources/c/main/firewall.c new file mode 100644 index 0000000..3956a1d --- /dev/null +++ b/sources/c/main/firewall.c @@ -0,0 +1,53 @@ +#include "firewall.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_firewall_main_ + void firewall_main(firewall_main_t * const main) { + + if (!main || F_status_is_error(main->setting.state.status)) return; + + main->setting.state.status = F_okay; + + if (main->setting.flag & firewall_main_flag_version_copyright_help_d) { + if (main->setting.flag & firewall_main_flag_help_d) { + firewall_print_message_help(&main->program.message); + } + else if (main->setting.flag & firewall_main_flag_version_d) { + fll_program_print_version(&main->program.message, firewall_program_version_s); + } + else if (main->setting.flag & firewall_main_flag_copyright_d) { + fll_program_print_copyright(&main->program.message, fll_program_copyright_year_author_s); + } + + if (main->program.signal_received) { + fll_program_print_signal_received(&main->program.warning, main->program.signal_received); + } + + return; + } + + if (main->setting.flag & firewall_main_flag_operation_d) { + firewall_operate(main); + } + else { + main->setting.state.status = F_status_set_error(F_parameter); + + firewall_print_error_operation_specified_not(&main->program.error); + } + + if (main->program.signal_received) { + fll_program_print_signal_received(&main->program.warning, main->program.signal_received); + } + + if (F_status_is_error(main->setting.state.status) || main->setting.state.status == F_interrupt) return; + + main->setting.state.status = F_okay; + } +#endif // _di_firewall_main_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/main/firewall.h b/sources/c/main/firewall.h new file mode 100644 index 0000000..47f0468 --- /dev/null +++ b/sources/c/main/firewall.h @@ -0,0 +1,100 @@ +/** + * FLL - Level 3 + * + * Project: Firewall + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * This is the program is intended to be used to manage iptables. + * + * This program utilizes the Featureless Linux Library. + */ +#ifndef _firewall_h +#define _firewall_h + +// Libc includes. +#include + +// FLL-0 includes. +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// FLL-1 includes. +#include + +// FLL-2 includes. +#include +#include +#include +#include +#include +#include +#include +#include + +// Firewall includes. +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Execute main program. + * + * @param main + * The main program and setting data. + * + * This alters main.setting.state.status: + * F_okay on success. + * + * F_interrupt (with error bit) on interrupt signal received. + * + * Errors (with error bit) from: f_file_stream_open() + * Errors (with error bit) from: firewall_load_line() + * Errors (with error bit) from: firewall_process() + * + * @see f_file_stream_open() + * @see firewall_load_line() + * @see firewall_process() + */ +#ifndef _di_firewall_main_ + extern void firewall_main(firewall_main_t * const main); +#endif // _di_firewall_main_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _firewall_h diff --git a/sources/c/main/main.c b/sources/c/main/main.c new file mode 100644 index 0000000..9cfcb47 --- /dev/null +++ b/sources/c/main/main.c @@ -0,0 +1,75 @@ +#include "firewall.h" + +int main(const int argc, const f_string_t *argv, const f_string_t *envp) { + + firewall_main_t data = firewall_main_t_initialize; + + data.program.debug.flag |= firewall_print_flag_debug_e | firewall_print_flag_out_e; + data.program.error.flag |= firewall_print_flag_error_e | firewall_print_flag_out_e; + data.program.output.flag |= firewall_print_flag_out_e; + data.program.message.flag |= firewall_print_flag_message_e | firewall_print_flag_out_e; + data.program.warning.flag |= firewall_print_flag_warning_e | firewall_print_flag_out_e; + data.program.error.custom = (void *) &data; + data.program.debug.custom = (void *) &data; + data.program.message.custom = (void *) &data; + data.program.output.custom = (void *) &data; + data.program.warning.custom = (void *) &data; + + f_console_parameter_t parameters[] = firewall_console_parameter_t_initialize; + + data.program.parameters.array = parameters; + data.program.parameters.used = firewall_parameter_total_d; + data.program.environment = envp; + + data.setting.flag |= firewall_main_flag_ipv46_d; + + if (f_pipe_input_exists()) { + data.program.pipe = fll_program_data_pipe_input_e; + } + + fll_program_standard_set_up(&data.program); + + f_file_umask_get(&data.program.umask); + + #ifdef _di_thread_support_ + { + const f_console_arguments_t arguments = macro_f_console_arguments_t_initialize_1(argc, argv, envp); + + firewall_setting_load(arguments, &data); + } + + firewall_main(&data); + #else + { + f_thread_id_t id_signal; + + memset(&id_signal, 0, sizeof(f_thread_id_t)); + + data.setting.state.status = f_thread_create(0, &id_signal, &firewall_thread_signal, (void *) &data); + + if (F_status_is_error(data.setting.state.status)) { + firewall_print_error(&data.program.error, F_status_debug_source_d); + } + else { + { + const f_console_arguments_t arguments = macro_f_console_arguments_t_initialize_1(argc, argv, envp); + + firewall_setting_load(arguments, &data); + } + + if (!macro_firewall_signal_check(&data.program, &data.setting.state)) { + firewall_main(&data); + } + + f_thread_cancel(id_signal); + f_thread_join(id_signal, 0); + } + } + #endif // _di_thread_support_ + + firewall_main_delete(&data); + + fll_program_standard_set_down(&data.program); + + return (F_status_is_error(data.setting.state.status) || data.setting.state.status == F_false) ? 1 : 0; +} diff --git a/sources/c/main/main.h b/sources/c/main/main.h new file mode 100644 index 0000000..02816c1 --- /dev/null +++ b/sources/c/main/main.h @@ -0,0 +1,38 @@ +/** + * FLL - Level 3 + * + * Project: Firewall + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * This file is only ever included by main/main.c and should not normally be included anywhere else. + * Anything that wants to include this should be providing the "firewall" program functionality in some manner. + */ +#ifndef _firewall_main_h +#define _firewall_main_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Standard program entry point. + * + * @param argc + * The number of arguments. + * @param argv + * The array of arguments. + * @param envp + * The array of all environment variables on program start. + * + * @return + * 0 on success. + * 1 on error. + */ +extern int main(const int argc, const f_string_t *argv, const f_string_t *envp); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _firewall_main_h diff --git a/sources/c/main/operate.c b/sources/c/main/operate.c new file mode 100644 index 0000000..dddf91a --- /dev/null +++ b/sources/c/main/operate.c @@ -0,0 +1,246 @@ +#include "firewall.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_firewall_operate_ + void firewall_operate(firewall_main_t * const main) { + + if (!main) return; + + main->data.is = firewall_data_is_global_d; + + if (main->setting.flag & firewall_main_flag_operation_show_d) { + firewall_operate_show(main); + + return; + } + + main->setting.state.status = f_directory_list(firewall_network_devices_s, 0, alphasort, &main->setting.devices); + + if (F_status_is_error(main->setting.state.status)) { + if (F_status_set_fine(main->setting.state.status) == F_data_not) { + firewall_print_error_network_device_none(&main->program.error); + } + else if (F_status_set_fine(main->setting.state.status) == F_failure) { + firewall_print_error_file(&main->program.error, F_status_debug_source_d, firewall_network_devices_s, f_file_operation_read_s, fll_error_file_type_directory_e); + } + else { + firewall_print_error(&main->program.error, F_status_debug_source_d); + } + + return; + } + + f_number_unsigned_t i = 0; + + // Remove "lo" (loopback) from the device listing. + for (; i < main->setting.devices.used; ++i) { + + if (macro_firewall_signal_check(&main->program, &main->setting.state)) return; + + if (f_compare_dynamic(firewall_device_loop_s, main->setting.devices.array[i]) == F_equal_to) { + main->data.file = main->setting.devices.array[i]; + + for (--main->setting.devices.used; i < main->setting.devices.used; ++i) { + main->setting.devices.array[i] = main->setting.devices.array[i + 1]; + } // for + + main->setting.devices.array[main->setting.devices.used] = main->data.file; + } + } // for + + main->data.file.string = 0; + main->data.file.used = 0; + + if (main->setting.flag & firewall_main_flag_operation_stop_restart_lock_d) { + main->data.file.used = firewall_network_firewall_path_s.used + firewall_file_other_s.used; + + f_char_t path_file_other[main->data.file.used + 1]; + main->data.file.string = path_file_other; + path_file_other[main->data.file.used] = 0; + + memcpy(path_file_other, firewall_network_firewall_path_s.string, sizeof(f_char_t) * firewall_network_firewall_path_s.used); + memcpy(path_file_other + firewall_network_firewall_path_s.used, firewall_file_other_s.string, sizeof(f_char_t) * firewall_file_other_s.used); + + firewall_operate_buffer_chain(main, main->data.file, F_false); + if (F_status_is_error(main->setting.state.status) || main->setting.state.status == F_child) return; + + for (i = 0; i < main->data.chain_objects.used; ++i) { + + if (macro_firewall_signal_check(&main->program, &main->setting.state)) return; + + if (!(main->data.has & firewall_data_has_stop_e) && f_compare_dynamic_partial_string(firewall_group_stop_s.string, main->data.buffer, firewall_group_stop_s.used, main->data.chain_objects.array[i]) == F_equal_to) { + main->data.stop = i; + main->data.has |= firewall_data_has_stop_e; + } + else if (!(main->data.has & firewall_data_has_lock_e) && f_compare_dynamic_partial_string(firewall_group_lock_s.string, main->data.buffer, firewall_group_lock_s.used, main->data.chain_objects.array[i]) == F_equal_to) { + main->data.lock = i; + main->data.has |= firewall_data_has_lock_e; + } + } // for + + if (main->setting.flag & firewall_main_flag_operation_lock_d) { + if (main->data.has & firewall_data_has_lock_e) { + firewall_operate_delete_chains(main); + + firewall_operate_default_lock(main); + + if (F_status_is_error(main->setting.state.status) || main->setting.state.status == F_child) return; + + main->data.chain = main->data.lock; + main->data.is = firewall_data_is_lock_d; + main->data.range.start = main->data.chain_contents.array[main->data.lock].array[0].start; + main->data.range.stop = main->data.chain_contents.array[main->data.lock].array[0].stop; + + firewall_operate_buffer_rules(main); + + firewall_operate_rules(main); + } + else { + main->setting.state.status = F_status_set_error(F_data); + + firewall_print_error_operation_files_missing(&main->program.error, firewall_operation_lock_s, main->data.file); + } + + return; + } + + if (main->setting.flag & firewall_main_flag_operation_stop_restart_d) { + if (main->data.has & firewall_data_has_stop_e) { + firewall_operate_delete_chains(main); + + firewall_operate_default_lock(main); + + if (F_status_is_error(main->setting.state.status) || main->setting.state.status == F_child) return; + + main->data.chain = main->data.stop; + main->data.is = firewall_data_is_global_d | firewall_data_is_stop_d; + main->data.range.start = main->data.chain_contents.array[main->data.stop].array[0].start; + main->data.range.stop = main->data.chain_contents.array[main->data.stop].array[0].stop; + + firewall_operate_buffer_rules(main); + + firewall_operate_rules(main); + + if (F_status_is_error(main->setting.state.status) || (main->data.has & firewall_main_flag_operation_stop_d) || main->setting.state.status == F_child) return; + } + else { + main->setting.state.status = F_status_set_error(F_data); + + firewall_print_error_operation_files_missing(&main->program.error, firewall_operation_stop_s, main->data.file); + + return; + } + } + + main->data.file.string = 0; + main->data.file.used = 0; + } + + if (main->setting.flag & firewall_main_flag_operation_start_restart_d) { + main->data.file.used = firewall_network_firewall_path_s.used + firewall_file_first_s.used; + + f_char_t path_file_first[main->data.file.used + 1]; + main->data.file.string = path_file_first; + path_file_first[main->data.file.used] = 0; + + memcpy(path_file_first, firewall_network_firewall_path_s.string, sizeof(f_char_t) * firewall_network_firewall_path_s.used); + memcpy(path_file_first + firewall_network_firewall_path_s.used, firewall_file_first_s.string, sizeof(f_char_t) * firewall_file_first_s.used); + + firewall_operate_buffer_chain(main, main->data.file, F_false); + + if (main->setting.flag & firewall_main_flag_operation_start_d) { + firewall_operate_delete_chains(main); + + firewall_operate_default_lock(main); + } + + firewall_operate_create_custom_chains(main); + + main->data.is = firewall_data_is_global_d; + + firewall_operate_chains(main); + + if (F_status_is_error(main->setting.state.status) || main->setting.state.status == F_child || (main->setting.flag & firewall_main_flag_operation_stop_d)) return; + + for (f_number_unsigned_t j = 0; j < main->setting.devices.used; ++j) { + + if (macro_firewall_signal_check(&main->program, &main->setting.state)) return; + + main->cache.path_file.used = 0; + main->data.device = j; + + main->setting.state.status = f_memory_array_increase_by(firewall_network_firewall_path_s.used + main->setting.devices.array[j].used + firewall_file_suffix_s.used + 1, sizeof(f_char_t), (void **) &main->cache.path_file.string, &main->cache.path_file.used, &main->cache.path_file.size); + + if (F_status_is_error(main->setting.state.status)) { + firewall_print_error(&main->program.error, F_status_debug_source_d); + + return; + } + + main->data.file = main->cache.path_file; + + main->setting.state.status = f_string_dynamic_append(firewall_network_firewall_path_s, &main->cache.path_file); + + if (F_status_is_error_not(main->setting.state.status)) { + main->setting.state.status = f_string_dynamic_append(main->setting.devices.array[j], &main->cache.path_file); + } + + if (F_status_is_error_not(main->setting.state.status)) { + main->setting.state.status = f_string_dynamic_append(firewall_file_suffix_s, &main->cache.path_file); + } + + if (F_status_is_error(main->setting.state.status)) { + firewall_print_error(&main->program.error, F_status_debug_source_d); + + return; + } + + firewall_operate_buffer_chain(main, main->cache.path_file, F_true); + + firewall_operate_create_custom_chains(main); + + main->data.is = 0; + + firewall_operate_chains(main); + if (F_status_is_error(main->setting.state.status) || main->setting.state.status == F_child || (main->setting.flag & firewall_main_flag_operation_stop_d)) return; + } // for + + main->cache.path_file.used = 0; + + main->setting.state.status = f_string_dynamic_append(firewall_network_firewall_path_s, &main->cache.path_file); + + if (F_status_is_error_not(main->setting.state.status)) { + main->setting.state.status = f_string_dynamic_append(firewall_file_last_s, &main->cache.path_file); + } + + if (F_status_is_error(main->setting.state.status)) { + firewall_print_error(&main->program.error, F_status_debug_source_d); + + return; + } + + main->data.file.used = main->cache.path_file.used; + + firewall_operate_buffer_chain(main, main->cache.path_file, F_false); + + firewall_operate_create_custom_chains(main); + + main->data.is = firewall_data_is_global_d; + + firewall_operate_chains(main); + if (F_status_is_error(main->setting.state.status) || main->setting.state.status == F_child) return; + + main->data.file.string = 0; + main->data.file.used = 0; + } + + main->setting.state.status = F_okay; + } +#endif // _di_firewall_operate_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/main/operate.h b/sources/c/main/operate.h new file mode 100644 index 0000000..a62d0b3 --- /dev/null +++ b/sources/c/main/operate.h @@ -0,0 +1,59 @@ +/** + * FLL - Level 3 + * + * Project: Firewall + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Provides operate functionality. + * + * This is auto-included and should not need to be explicitly included. + */ +#ifndef _firewall_operate_h +#define _firewall_operate_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Perform the firewall operation. + * + * @param main + * The main program and setting data. + * + * This alters main.setting.state.status: + * F_okay on success. + * F_child on child process exiting. + * + * F_interrupt (with error bit) on interrupt signal received. + * + * Errors (with error bit) from: f_directory_list() + * Errors (with error bit) from: f_memory_array_increase_by() + * Errors (with error bit) from: firewall_operate_buffer_chain() + * Errors (with error bit) from: firewall_operate_create_custom_chains() + * Errors (with error bit) from: firewall_operate_default_lock() + * Errors (with error bit) from: firewall_operate_delete_chains() + * Errors (with error bit) from: firewall_operate_rules() + * Errors (with error bit) from: firewall_operate_process_rules() + * Errors (with error bit) from: firewall_operate_show() + * + * @see f_directory_list() + * @see f_memory_array_increase_by() + * @see firewall_operate_buffer_chain() + * @see firewall_operate_create_custom_chains() + * @see firewall_operate_default_lock() + * @see firewall_operate_delete_chains() + * @see firewall_operate_rules() + * @see firewall_operate_process_rules() + * @see firewall_operate_show() + */ +#ifndef _di_firewall_operate_ + extern void firewall_operate(firewall_main_t * const main); +#endif // _di_firewall_operate_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _firewall_operate_h diff --git a/sources/c/main/operate/buffer.c b/sources/c/main/operate/buffer.c new file mode 100644 index 0000000..a5728de --- /dev/null +++ b/sources/c/main/operate/buffer.c @@ -0,0 +1,100 @@ +#include "../firewall.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_firewall_operate_buffer_chain_ + void firewall_operate_buffer_chain(firewall_main_t * const main, const f_string_static_t file, const bool optional) { + + if (!main || F_status_is_error_not(main->setting.state.status) && main->setting.state.status == F_child) return; + + main->data.buffer.used = 0; + main->data.chain_contents.used = 0; + main->data.chain_objects.used = 0; + main->cache.delimits.used = 0; + + main->setting.state.status = f_file_open(file, 0, &main->cache.file); + + if (F_status_is_error(main->setting.state.status)) { + if (!optional || optional && F_status_set_fine(main->setting.state.status) != F_file_found_not && F_status_set_fine(main->setting.state.status) != F_file_open && F_status_set_fine(main->setting.state.status) != F_file_descriptor) { + firewall_print_error_file(&main->program.error, F_status_debug_source_d, file, f_file_operation_open_s, fll_error_file_type_file_e); + + return; + } + } + + main->setting.state.status = f_file_read(main->cache.file, &main->data.buffer); + + f_file_stream_flush(main->cache.file); + f_file_stream_close(&main->cache.file); + + if (F_status_is_error(main->setting.state.status)) { + firewall_print_error_file(&main->program.error, F_status_debug_source_d, file, f_file_operation_read_s, fll_error_file_type_file_e); + + return; + } + + if (main->data.buffer.used) { + main->data.range.start = 0; + main->data.range.stop = main->data.buffer.used - 1; + + fll_fss_basic_list_read(main->data.buffer, &main->data.range, &main->data.chain_objects, &main->data.chain_contents, &main->cache.delimits, 0, &main->data.comments, &main->setting.state); + + if (F_status_is_error(main->setting.state.status)) { + if (F_status_set_fine(main->setting.state.status) == F_data_not_eos || F_status_set_fine(main->setting.state.status) == F_data_not || F_status_set_fine(main->setting.state.status) == F_data_not_stop) { + firewall_print_error_file_empty(&main->program.error, file); + } + else { + firewall_print_error_file(&main->program.error, F_status_debug_source_d, file, f_file_operation_process_s, fll_error_file_type_file_e); + } + + return; + } + else { + f_fss_apply_delimit(main->cache.delimits, &main->data.buffer, &main->setting.state); + + if (F_status_is_error(main->setting.state.status)) { + firewall_print_error(&main->program.error, F_status_debug_source_d); + + return; + } + } + } + + main->setting.state.status = F_okay; + } +#endif // _di_firewall_operate_buffer_chain_ + +#ifndef _di_firewall_operate_buffer_rules_ + void firewall_operate_buffer_rules(firewall_main_t * const main) { + + if (!main || F_status_is_error_not(main->setting.state.status) && main->setting.state.status == F_child) return; + + main->cache.delimits.used = 0; + main->data.rule_contents.used = 0; + main->data.rule_objects.used = 0; + + fll_fss_extended_read(main->data.buffer, &main->data.range, &main->data.rule_objects, &main->data.rule_contents, 0, 0, &main->cache.delimits, 0, &main->setting.state); + + if (F_status_is_error(main->setting.state.status)) { + firewall_print_error(&main->program.error, F_status_debug_source_d); + + return; + } + + f_fss_apply_delimit(main->cache.delimits, &main->data.buffer, &main->setting.state); + + if (F_status_is_error(main->setting.state.status)) { + firewall_print_error(&main->program.error, F_status_debug_source_d); + + return; + } + + main->setting.state.status = F_okay; + } +#endif // _di_firewall_operate_buffer_rules_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/main/operate/buffer.h b/sources/c/main/operate/buffer.h new file mode 100644 index 0000000..eb48406 --- /dev/null +++ b/sources/c/main/operate/buffer.h @@ -0,0 +1,95 @@ +/** + * FLL - Level 3 + * + * Project: Firewall + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Provides the operate buffer functionality. + * + * This is auto-included and should not need to be explicitly included. + */ +#ifndef _firewall_operate_buffer_h +#define _firewall_operate_buffer_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Buffer firewall chain. + * + * The rules being processed are selected from main.data.range within main.data.buffer. + * Delimits are applied to the main.data.buffer on success. + * + * @param main + * The main program and setting data. + * + * This alters: + * - main.cache.delimits. + * - main.data.buffer. + * - main.data.chain_contents. + * - main.data.chain_objects. + * + * This alters main.setting.state.status: + * F_okay on success. + * F_child on child process exiting. + * + * F_interrupt (with error bit) on interrupt signal received. + * + * Errors (with error bit) from: f_file_open() + * Errors (with error bit) from: f_file_read() + * Errors (with error bit) from: f_fss_apply_delimit() + * Errors (with error bit) from: fll_fss_basic_list_read() + * @param file + * File name to read the rules from. + * @param optional + * TRUE if this files is optional. + * FALSE otherwise (more are errors returned when not optional). + * + * @see f_file_open() + * @see f_file_read() + * @see f_fss_apply_delimit() + * @see fll_fss_basic_list_read() + */ +#ifndef _di_firewall_operate_buffer_chain_ + extern void firewall_operate_buffer_chain(firewall_main_t * const main, const f_string_static_t file, const bool optional); +#endif // _di_firewall_operate_buffer_chain_ + +/** + * Buffer firewall rules. + * + * The rules being processed are selected from main.data.range within main.data.buffer. + * Delimits are applied to the main.data.buffer on success. + * + * @param main + * The main program and setting data. + * + * This alters: + * - main.cache.delimits. + * - main.data.buffer. + * - main.data.rule_contents. + * - main.data.rule_objects. + * + * This alters main.setting.state.status: + * F_okay on success. + * + * F_interrupt (with error bit) on interrupt signal received. + * + * Errors (with error bit) from: f_fss_apply_delimit() + * Errors (with error bit) from: firewall_operate_process_rules() + * Errors (with error bit) from: fll_fss_extended_read() + * + * @see f_fss_apply_delimit() + * @see firewall_operate_process_rules() + * @see fll_fss_extended_read() + */ +#ifndef _di_firewall_operate_buffer_rules_ + extern void firewall_operate_buffer_rules(firewall_main_t * const main); +#endif // _di_firewall_operate_buffer_rules_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _firewall_operate_buffer_h diff --git a/sources/c/main/operate/chains.c b/sources/c/main/operate/chains.c new file mode 100644 index 0000000..e920aba --- /dev/null +++ b/sources/c/main/operate/chains.c @@ -0,0 +1,38 @@ +#include "../firewall.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_firewall_operate_chains_ + void firewall_operate_chains(firewall_main_t * const main) { + + if (!main || F_status_is_error_not(main->setting.state.status) && main->setting.state.status == F_child) return; + + for (f_number_unsigned_t i = 0; i < main->data.chain_contents.used; ++i) { + + main->data.range = main->data.chain_contents.array[i].array[0]; + + if ((main->data.has & firewall_data_has_main_e) && i == main->data.main) { + main->data.is |= firewall_data_is_main_d; + } + else { + main->data.is &= ~firewall_data_is_main_d; + } + + main->data.chain = i; + + firewall_operate_buffer_rules(main); + + firewall_operate_rules(main); + + if (F_status_is_error(main->setting.state.status) || (main->setting.flag & firewall_main_flag_operation_stop_d) || main->setting.state.status == F_child) return; + } // for + + main->setting.state.status = F_okay; + } +#endif // _di_firewall_operate_chains_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/main/operate/chains.h b/sources/c/main/operate/chains.h new file mode 100644 index 0000000..6c80b75 --- /dev/null +++ b/sources/c/main/operate/chains.h @@ -0,0 +1,46 @@ +/** + * FLL - Level 3 + * + * Project: Firewall + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Provides the operate chains functionality. + * + * This is auto-included and should not need to be explicitly included. + */ +#ifndef _firewall_operate_chains_h +#define _firewall_operate_chains_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Load and operate the each of the Content chains. + * + * @param main + * The main program and setting data. + * + * This alters: + * - main.data.is. + * - main.data.range. + * + * This alters main.setting.state.status: + * F_okay on success. + * + * F_interrupt (with error bit) on interrupt signal received. + * + * Errors (with error bit) from: firewall_operate_rules() + * + * @see firewall_operate_rules() + */ +#ifndef _di_firewall_operate_chains_ + extern void firewall_operate_chains(firewall_main_t * const main); +#endif // _di_firewall_operate_chains_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _firewall_operate_chains_h diff --git a/sources/c/main/operate/create.c b/sources/c/main/operate/create.c new file mode 100644 index 0000000..ff6d37b --- /dev/null +++ b/sources/c/main/operate/create.c @@ -0,0 +1,227 @@ +#include "../firewall.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_firewall_operate_create_custom_chains_ + void firewall_operate_create_custom_chains(firewall_main_t * const main) { + + if (!main || F_status_is_error_not(main->setting.state.status) && main->setting.state.status == F_child) return; + + uint8_t new_chain = F_false; + uint8_t create_chain = F_false; + + int return_code = 0; + f_number_unsigned_t i = 0; + f_number_unsigned_t j = 0; + f_number_unsigned_t t = 0; + f_number_unsigned_t length = 0; + + const f_string_static_t tools[2] = { main->setting.flag & firewall_main_flag_ipv4_d ? firewall_tool_iptables_s : f_string_empty_s, main->setting.flag & firewall_main_flag_ipv6_d ? firewall_tool_ip6tables_s : f_string_empty_s }; + + main->data.chain_ids.used = 0; + main->cache.arguments.used = 0; + + main->setting.state.status = f_memory_array_increase_by(2, sizeof(f_string_dynamic_t), (void **) &main->cache.arguments.array, &main->cache.arguments.used, &main->cache.arguments.size); + + if (F_status_is_error_not(main->setting.state.status)) { + main->setting.state.status = f_memory_array_increase_by(main->data.chain_objects.used, sizeof(f_number_unsigned_t), (void **) &main->data.chain_ids.array, &main->data.chain_ids.used, &main->data.chain_ids.size); + } + + if (F_status_is_error(main->setting.state.status)) { + firewall_print_error(&main->program.error, F_status_debug_source_d); + + return; + } + + main->cache.arguments.array[0].used = 0; + main->cache.arguments.array[1].used = 0; + main->data.chain_ids.used = main->data.chain_objects.used; + memset(main->data.chain_ids.array, 0, sizeof(f_number_unsigned_t) * main->data.chain_ids.used); + + main->setting.state.status = f_string_dynamic_append(firewall_chain_create_operation_s, &main->cache.arguments.array[0]); + + if (F_status_is_error(main->setting.state.status)) { + firewall_print_error(&main->program.error, F_status_debug_source_d); + + return; + } + + main->setting.state.status = f_memory_array_increase(F_memory_default_allocation_small_d, sizeof(f_char_t), (void **) &main->cache.arguments.array[1].string, &main->cache.arguments.array[1].used, &main->cache.arguments.array[1].size); + + if (F_status_is_error(main->setting.state.status)) { + firewall_print_error(&main->program.error, F_status_debug_source_d); + + return; + } + + main->cache.arguments.used = 2; + main->data.has = 0; + + for (; i < main->data.chain_objects.used; ++i) { + + if (macro_firewall_signal_check(&main->program, &main->setting.state)) return; + + new_chain = F_true; + j = 0; + + // Skip globally reserved chain name: main. + if (f_compare_dynamic_partial_string(firewall_group_main_s.string, main->data.buffer, firewall_group_main_s.used, main->data.chain_objects.array[i]) == F_equal_to) { + new_chain = F_false; + main->data.has |= firewall_data_has_main_e; + main->data.main = i; + } + + // Skip globally reserved chain name: stop. + if (f_compare_dynamic_partial_string(firewall_group_stop_s.string, main->data.buffer, firewall_group_stop_s.used, main->data.chain_objects.array[i]) == F_equal_to) { + new_chain = F_false; + main->data.has |= firewall_data_has_stop_e; + main->data.stop = i; + } + + // Skip globally reserved chain name: lock. + if (f_compare_dynamic_partial_string(firewall_group_lock_s.string, main->data.buffer, firewall_group_lock_s.used, main->data.chain_objects.array[i]) == F_equal_to) { + new_chain = F_false; + main->data.has |= firewall_data_has_lock_e; + main->data.lock = i; + } + + // Skip globally reserved chain name: none. + if (f_compare_dynamic_partial_string(firewall_chain_none_s.string, main->data.buffer, firewall_chain_none_s.used, main->data.chain_objects.array[i]) == F_equal_to) { + new_chain = F_false; + } + + if (new_chain) { + for (; j < main->setting.chains.used; ++j) { + + if (f_compare_dynamic_partial_string(main->setting.chains.array[j].string, main->data.buffer, main->setting.chains.array[j].used, main->data.chain_objects.array[i]) == F_equal_to) { + new_chain = F_false; + main->data.chain_ids.array[i] = j; + + break; + } + } // for + } + + if (new_chain) { + main->setting.state.status = f_memory_array_increase(firewall_allocation_small_d, sizeof(f_string_dynamic_t), (void **) &main->setting.chains.array, &main->setting.chains.used, &main->setting.chains.size); + + if (F_status_is_error(main->setting.state.status)) { + firewall_print_error(&main->program.error, F_status_debug_source_d); + + return; + } + + create_chain = F_true; + length = (main->data.chain_objects.array[i].start > main->data.chain_objects.array[i].stop) ? 0 : (main->data.chain_objects.array[i].stop - main->data.chain_objects.array[i].start) + 1; + + main->cache.arguments.array[1].used = 0; + + main->setting.state.status = f_memory_array_increase_by(length + 1, sizeof(f_char_t), (void **) &main->cache.arguments.array[1].string, &main->cache.arguments.array[1].used, &main->cache.arguments.array[1].size); + + if (F_status_is_error_not(main->setting.state.status)) { + main->setting.state.status = f_memory_array_increase_by(length + 1, sizeof(f_char_t), (void **) &main->setting.chains.array[main->setting.chains.used].string, &main->setting.chains.array[main->setting.chains.used].used, &main->setting.chains.array[main->setting.chains.used].size); + } + + if (F_status_is_error(main->setting.state.status)) { + firewall_print_error(&main->program.error, F_status_debug_source_d); + + return; + } + + f_string_dynamic_partial_append_nulless(main->data.buffer, main->data.chain_objects.array[i], &main->cache.arguments.array[1]); + + if (F_status_is_error_not(main->setting.state.status)) { + f_string_dynamic_partial_append_nulless(main->data.buffer, main->data.chain_objects.array[i], &main->setting.chains.array[main->setting.chains.used]); + } + + if (F_status_is_error(main->setting.state.status)) { + firewall_print_error(&main->program.error, F_status_debug_source_d); + + return; + } + + f_string_dynamic_terminate_after(&main->cache.arguments.array[1]); + + if (F_status_is_error_not(main->setting.state.status)) { + f_string_dynamic_terminate_after(&main->setting.chains.array[main->setting.chains.used]); + } + + if (F_status_is_error(main->setting.state.status)) { + firewall_print_error(&main->program.error, F_status_debug_source_d); + + return; + } + + main->data.chain_ids.array[i] = main->setting.chains.used; + + if (f_compare_dynamic(main->cache.arguments.array[1], firewall_chain_forward_s) == F_equal_to) { + create_chain = F_false; + } + else if (f_compare_dynamic(main->cache.arguments.array[1], firewall_chain_input_s) == F_equal_to) { + create_chain = F_false; + } + else if (f_compare_dynamic(main->cache.arguments.array[1], firewall_chain_output_s) == F_equal_to) { + create_chain = F_false; + } + else if (f_compare_dynamic(main->cache.arguments.array[1], firewall_chain_postrouting_s) == F_equal_to) { + create_chain = F_false; + } + else if (f_compare_dynamic(main->cache.arguments.array[1], firewall_chain_prerouting_s) == F_equal_to) { + create_chain = F_false; + } + + if (create_chain) { + for (t = 0; t < 2; ++t) { + + if (!tools[t].used) continue; + + return_code = 0; + + firewall_print_debug_tool(&main->program.warning, tools[t], main->cache.arguments); + + main->setting.state.status = fll_execute_program(tools[t], main->cache.arguments, 0, 0, (void *) &return_code); + + if (main->setting.state.status == F_child) { + main->program.child = return_code; + + return; + } + + if (macro_firewall_signal_check(&main->program, &main->setting.state)) return; + + if (return_code && F_status_is_error_not(main->setting.state.status)) { + firewall_print_error_operation_return_code(&main->program.error, tools[t], main->cache.arguments, return_code); + } + + if (main->setting.state.status == F_child) { + main->program.child = return_code; + + return; + } + + if (F_status_is_error(main->setting.state.status)) { + if (F_status_set_fine(main->setting.state.status) == F_failure) { + firewall_print_error_operation(&main->program.error, tools[t], main->cache.arguments); + } + else { + firewall_print_error(&main->program.error, F_status_debug_source_d); + } + + return; + } + } // for + } + + ++main->setting.chains.used; + } + } // for + + main->setting.state.status = F_okay; + } +#endif // _di_firewall_operate_create_custom_chains_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/main/operate/create.h b/sources/c/main/operate/create.h new file mode 100644 index 0000000..306b74e --- /dev/null +++ b/sources/c/main/operate/create.h @@ -0,0 +1,54 @@ +/** + * FLL - Level 3 + * + * Project: Firewall + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Provides the operate create functionality. + * + * This is auto-included and should not need to be explicitly included. + */ +#ifndef _firewall_operate_create_h +#define _firewall_operate_create_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Apply firewall rules for creating custom chains. + * + * @param main + * The main program and setting data. + * + * This alters main.setting.state.status: + * F_okay on success. + * F_child on child process exiting. + * + * F_interrupt (with error bit) on interrupt signal received. + * + * Errors (with error bit) from: f_memory_array_increase() + * Errors (with error bit) from: f_memory_array_increase_by() + * Errors (with error bit) from: f_string_dynamic_append() + * Errors (with error bit) from: fll_execute_program() + * @param file + * File name to read the rules from. + * @param optional + * TRUE if this files is optional. + * FALSE otherwise (more are errors returned when not optional). + * + * @see f_memory_array_increase() + * @see f_memory_array_increase_by() + * @see f_string_dynamic_append() + * @see fll_execute_program() + */ +#ifndef _di_firewall_operate_create_custom_chains_ + extern void firewall_operate_create_custom_chains(firewall_main_t * const main); +#endif // _di_firewall_operate_create_custom_chains_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _firewall_operate_create_h diff --git a/sources/c/main/operate/default.c b/sources/c/main/operate/default.c new file mode 100644 index 0000000..3dbb2c5 --- /dev/null +++ b/sources/c/main/operate/default.c @@ -0,0 +1,73 @@ +#include "../firewall.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_firewall_operate_default_lock_ + void firewall_operate_default_lock(firewall_main_t * const main) { + + if (!main || F_status_is_error_not(main->setting.state.status) && main->setting.state.status == F_child) return; + + const f_string_static_t chains[3] = { firewall_chain_input_s, firewall_chain_output_s, firewall_chain_forward_s }; + const f_string_static_t tools[2] = { main->setting.flag & firewall_main_flag_ipv4_d ? firewall_tool_iptables_s : f_string_empty_s, main->setting.flag & firewall_main_flag_ipv6_d ? firewall_tool_ip6tables_s : f_string_empty_s }; + + f_string_statics_t arguments = f_string_statics_t_initialize; + arguments.used = 3; + + f_string_static_t argument_array[arguments.used]; + arguments.array = argument_array; + arguments.array[0] = firewall_action_policy_operation_s; + arguments.array[2] = firewall_chain_drop_s; + + int return_code = 0; + uint8_t i = 0; + uint8_t t = 0; + + for (; i < 3; ++i) { + + arguments.array[1] = chains[i]; + + for (t = 0; t < 2; ++t) { + + if (macro_firewall_signal_check(&main->program, &main->setting.state)) return; + + if (!tools[t].used) continue; + + firewall_print_debug_tool(&main->program.warning, tools[t], arguments); + + return_code = 0; + + main->setting.state.status = fll_execute_program(tools[t], arguments, 0, 0, (void *) &return_code); + + if (main->setting.state.status == F_child) { + main->program.child = return_code; + + return; + } + + if (macro_firewall_signal_check(&main->program, &main->setting.state)) return; + + if (F_status_is_error(main->setting.state.status)) { + if (F_status_set_fine(main->setting.state.status) == F_failure) { + firewall_print_error_operation(&main->program.error, tools[t], arguments); + } + else { + firewall_print_error(&main->program.error, F_status_debug_source_d); + } + + return; + } + else if (return_code) { + firewall_print_error_operation_return_code(&main->program.error, tools[t], main->cache.arguments, return_code); + } + } // for + } // for + + main->setting.state.status = F_okay; + } +#endif // _di_firewall_operate_default_lock_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/main/operate/default.h b/sources/c/main/operate/default.h new file mode 100644 index 0000000..e9de3e8 --- /dev/null +++ b/sources/c/main/operate/default.h @@ -0,0 +1,45 @@ +/** + * FLL - Level 3 + * + * Project: Firewall + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Provides the operate default functionality. + * + * This is auto-included and should not need to be explicitly included. + */ +#ifndef _firewall_operate_default_h +#define _firewall_operate_default_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Apply firewall rules intended to lock down the firewall. + * + * This is intended to setup the firewall with rules that prevent access to or from the network. + * + * @param main + * The main program and setting data. + * + * This alters main.setting.state.status: + * F_okay on success. + * F_child on child process exiting. + * + * F_interrupt (with error bit) on interrupt signal received. + * + * Errors (with error bit) from: fll_execute_program() + * + * @see fll_execute_program() + */ +#ifndef _di_firewall_operate_default_lock_ + extern void firewall_operate_default_lock(firewall_main_t * const main); +#endif // _di_firewall_operate_default_lock_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _firewall_operate_default_h diff --git a/sources/c/main/operate/delete.c b/sources/c/main/operate/delete.c new file mode 100644 index 0000000..837908e --- /dev/null +++ b/sources/c/main/operate/delete.c @@ -0,0 +1,70 @@ +#include "../firewall.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_firewall_operate_delete_chains_ + void firewall_operate_delete_chains(firewall_main_t * const main) { + + if (!main || F_status_is_error_not(main->setting.state.status) && main->setting.state.status == F_child) return; + + const f_string_static_t tools[2] = { main->setting.flag & firewall_main_flag_ipv4_d ? firewall_tool_iptables_s : f_string_empty_s, main->setting.flag & firewall_main_flag_ipv6_d ? firewall_tool_ip6tables_s : f_string_empty_s }; + const f_string_static_t command[2] = { firewall_chain_flush_operation_s, firewall_chain_delete_operation_s }; + + f_string_statics_t arguments = f_string_statics_t_initialize; + arguments.used = 1; + + f_string_static_t argument_array[arguments.used]; + arguments.array = argument_array; + argument_array[0] = firewall_chain_flush_operation_s; + + int return_code = 0; + uint8_t i = 0; + uint8_t t = 0; + + for (i = 0; i < 2; ++i) { + + argument_array[0] = command[i]; + + for (t = 0; t < 2; ++t) { + + if (macro_firewall_signal_check(&main->program, &main->setting.state)) return; + + if (!tools[t].used) continue; + + return_code = 0; + + firewall_print_debug_tool(&main->program.warning, tools[t], arguments); + + main->setting.state.status = fll_execute_program(tools[t], arguments, 0, 0, (void *) &return_code); + + if (main->setting.state.status == F_child) { + main->program.child = return_code; + + return; + } + + if (F_status_is_error(main->setting.state.status)) { + if (F_status_set_fine(main->setting.state.status) == F_failure) { + firewall_print_error_operation(&main->program.error, tools[t], arguments); + } + else { + firewall_print_error(&main->program.error, F_status_debug_source_d); + } + + return; + } + else if (return_code) { + firewall_print_error_operation_return_code(&main->program.error, tools[t], main->cache.arguments, return_code); + } + } // for + } // for + + main->setting.state.status = F_okay; + } +#endif // _di_firewall_operate_delete_chains_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/main/operate/delete.h b/sources/c/main/operate/delete.h new file mode 100644 index 0000000..c177c93 --- /dev/null +++ b/sources/c/main/operate/delete.h @@ -0,0 +1,46 @@ +/** + * FLL - Level 3 + * + * Project: Firewall + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Provides the operate delete functionality. + * + * This is auto-included and should not need to be explicitly included. + */ +#ifndef _firewall_operate_delete_h +#define _firewall_operate_delete_h + +#ifdef __cplusplus +extern "C" { +#endif + + /** + * Unapply (remove) the firewall rules, deleting all existing firewall rules being used. + * + * This function is not about de-allocating memory. + * This function is not about modifying settings or files. + * + * @param main + * The main program and setting data. + * + * This alters main.setting.state.status: + * F_okay on success. + * F_child on child process exiting. + * + * F_interrupt (with error bit) on interrupt signal received. + * + * Errors (with error bit) from: fll_execute_program() + * + * @see fll_execute_program() + */ +#ifndef _di_firewall_operate_delete_chains_ + extern void firewall_operate_delete_chains(firewall_main_t * const main); +#endif // _di_firewall_operate_delete_chains_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _firewall_operate_delete_h diff --git a/sources/c/main/operate/process.c b/sources/c/main/operate/process.c new file mode 100644 index 0000000..dcdbd38 --- /dev/null +++ b/sources/c/main/operate/process.c @@ -0,0 +1,612 @@ +#include "../firewall.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_firewall_operate_process_rules_perform_ + void firewall_operate_process_rules(firewall_main_t * const main) { + + if (!main || F_status_is_error_not(main->setting.state.status) && main->setting.state.status == F_child) return; + + uint8_t valid = F_true; + uint8_t is_ip_list = F_false; + uint8_t ip_list_direction = F_false; // false = source, true = destination. + uint8_t use_protocol = F_false; + uint8_t chain = firewall_chain_none_e; + uint8_t direction = firewall_direction_none_e; + uint8_t action = firewall_action_append_e; + + int return_code = 0; + f_number_unsigned_t at = 0; + f_number_unsigned_t i = 0; + f_number_unsigned_t t = 0; + + // Set the default here, but allow for the firewall rules to override these settings. + f_string_static_t tools[2] = { main->setting.flag & firewall_main_flag_ipv4_d ? firewall_tool_iptables_s : f_string_empty_s, main->setting.flag & firewall_main_flag_ipv6_d ? firewall_tool_ip6tables_s : f_string_empty_s }; + + f_ranges_t * const rule_objects = &main->data.rule_objects; + f_rangess_t * const rule_contents = &main->data.rule_contents; + + if (!(main->data.is & firewall_data_is_global_d)) { + if (main->setting.devices.array[main->data.device].used) { + main->cache.device.used = 0; + + main->setting.state.status = f_string_dynamic_append(main->setting.devices.array[main->data.device], &main->cache.device); + if (F_status_is_error(main->setting.state.status)) return; + } + } + + // For custom chains, the chain command may not be specified. + if (!(main->data.is & firewall_data_is_stop_main_lock_d)) { + chain = firewall_chain_custom_e; + } + + for (; i < rule_objects->used; ++i) { + + if (macro_firewall_signal_check(&main->program, &main->setting.state)) return; + + valid = F_true; + is_ip_list = F_false; + ip_list_direction = F_false; + + main->cache.ip_list.used = 0; + + // Process chain rule. + if (f_compare_dynamic_partial_string(firewall_chain_s.string, main->data.buffer, firewall_chain_s.used, rule_objects->array[i]) == F_equal_to) { + if (chain == firewall_chain_custom_e) { + + // Custom chains can only apply to themselves, so silently ignore chain commands specified within a custom chain. + firewall_print_warning_chain_meaningless_line(&main->program.warning, i); + + continue; + } + + if (rule_contents->array[i].used != 1) { + valid = F_false; + } + else if (f_compare_dynamic_partial_string(firewall_chain_input_s.string, main->data.buffer, firewall_chain_input_s.used, rule_contents->array[i].array[0]) == F_equal_to) { + chain = firewall_chain_input_e; + } + else if (f_compare_dynamic_partial_string(firewall_chain_output_s.string, main->data.buffer, firewall_chain_output_s.used, rule_contents->array[i].array[0]) == F_equal_to) { + chain = firewall_chain_output_e; + } + else if (f_compare_dynamic_partial_string(firewall_chain_forward_s.string, main->data.buffer, firewall_chain_forward_s.used, rule_contents->array[i].array[0]) == F_equal_to) { + chain = firewall_chain_forward_e; + } + else if (f_compare_dynamic_partial_string(firewall_chain_postrouting_s.string, main->data.buffer, firewall_chain_postrouting_s.used, rule_contents->array[i].array[0]) == F_equal_to) { + chain = firewall_chain_postrouting_e; + } + else if (f_compare_dynamic_partial_string(firewall_chain_prerouting_s.string, main->data.buffer, firewall_chain_prerouting_s.used, rule_contents->array[i].array[0]) == F_equal_to) { + chain = firewall_chain_prerouting_e; + } + else if (f_compare_dynamic_partial_string(firewall_chain_none_s.string, main->data.buffer, firewall_chain_none_s.used, rule_contents->array[i].array[0]) == F_equal_to) { + chain = firewall_chain_none_e; + } + else { + valid = F_false; + } + + if (valid) continue; + } + + // Process direction rule + else if (f_compare_dynamic_partial_string(firewall_direction_s.string, main->data.buffer, firewall_direction_s.used, rule_objects->array[i]) == F_equal_to) { + if (rule_contents->array[i].used != 1) { + valid = F_false; + } + else if (f_compare_dynamic_partial_string(firewall_direction_input_s.string, main->data.buffer, firewall_direction_input_s.used, rule_contents->array[i].array[0]) == F_equal_to) { + direction = firewall_direction_input_e; + } + else if (f_compare_dynamic_partial_string(firewall_direction_output_s.string, main->data.buffer, firewall_direction_output_s.used, rule_contents->array[i].array[0]) == F_equal_to) { + direction = firewall_direction_output_e; + } + else if (f_compare_dynamic_partial_string(firewall_direction_none_s.string, main->data.buffer, firewall_direction_none_s.used, rule_contents->array[i].array[0]) == F_equal_to) { + direction = firewall_direction_none_e; + } + else { + + // Direction must be specified, and no custom directions are allowed. + valid = F_false; + } + + if (valid) continue; + } + + // Process device rule. + else if (f_compare_dynamic_partial_string(firewall_device_s.string, main->data.buffer, firewall_device_s.used, rule_objects->array[i]) == F_equal_to) { + if (rule_contents->array[i].used != 1) { + valid = F_false; + } + else if (f_compare_dynamic_partial_string(firewall_device_all_s.string, main->data.buffer, firewall_device_all_s.used, rule_contents->array[i].array[0]) == F_equal_to) { + main->cache.device.used = 0; + + continue; + } + else if (f_compare_dynamic_partial_string(firewall_device_this_s.string, main->data.buffer, firewall_device_this_s.used, rule_contents->array[i].array[0]) == F_equal_to) { + if (main->setting.devices.array[main->data.device].used) { + main->setting.state.status = f_string_dynamic_append(main->setting.devices.array[main->data.device], &main->cache.device); + } + else { + main->cache.device.used = 0; + } + + if (F_status_is_error(main->setting.state.status)) return; + + continue; + } + + if (valid) { + main->cache.device.used = 0; + + main->setting.state.status = f_string_dynamic_partial_append(main->data.buffer, rule_contents->array[i].array[0], &main->cache.device); + if (F_status_is_error(main->setting.state.status)) return; + + continue; + } + } + + // Process action rule. + else if (f_compare_dynamic_partial_string(firewall_action_s.string, main->data.buffer, firewall_action_s.used, rule_objects->array[i]) == F_equal_to) { + if (rule_contents->array[i].used != 1) { + valid = F_false; + } + else if (f_compare_dynamic_partial_string(firewall_action_append_s.string, main->data.buffer, firewall_action_append_s.used, rule_contents->array[i].array[0]) == F_equal_to) { + action = firewall_action_append_e; + } + else if (f_compare_dynamic_partial_string(firewall_action_insert_s.string, main->data.buffer, firewall_action_insert_s.used, rule_contents->array[i].array[0]) == F_equal_to) { + action = firewall_action_insert_e; + } + else if (f_compare_dynamic_partial_string(firewall_action_policy_s.string, main->data.buffer, firewall_action_policy_s.used, rule_contents->array[i].array[0]) == F_equal_to) { + action = firewall_action_policy_e; + } + else if (f_compare_dynamic_partial_string(firewall_action_none_s.string, main->data.buffer, firewall_action_none_s.used, rule_contents->array[i].array[0]) == F_equal_to) { + action = firewall_action_none_e; + } + else { + valid = F_false; + } + + if (valid) continue; + } + + // Process ip_list rule. + else if (f_compare_dynamic_partial_string(firewall_ip_list.string, main->data.buffer, firewall_ip_list.used, rule_objects->array[i]) == F_equal_to) { + is_ip_list = F_true; + + if (f_compare_dynamic_partial_string(firewall_ip_list_source_s.string, main->data.buffer, firewall_ip_list_source_s.used, rule_contents->array[i].array[0]) == F_equal_to) { + ip_list_direction = F_false; + } + else if (f_compare_dynamic_partial_string(firewall_ip_list_destination_s.string, main->data.buffer, firewall_ip_list_destination_s.used, rule_contents->array[i].array[0]) == F_equal_to) { + ip_list_direction = F_true; + } + else { + valid = F_false; + } + } + + // Process protocol rule. + else if (f_compare_dynamic_partial_string(firewall_protocol_s.string, main->data.buffer, firewall_protocol_s.used, rule_objects->array[i]) == F_equal_to) { + if (rule_contents->array[i].used != 1) { + valid = F_false; + } + else { + if (f_compare_dynamic_partial_string(firewall_protocol_none_s.string, main->data.buffer, firewall_protocol_none_s.used, rule_contents->array[i].array[0]) == F_equal_to) { + use_protocol = F_false; + } + else if (rule_contents->array[i].array[0].start <= rule_contents->array[i].array[0].stop) { + main->cache.protocol.used = 0; + + main->setting.state.status = f_string_dynamic_partial_append(main->data.buffer, rule_contents->array[i].array[0], &main->cache.protocol); + if (F_status_is_error(main->setting.state.status)) return; + + use_protocol = F_true; + } + else { + use_protocol = F_false; + } + + continue; + } + } + + // Process tool rule. + else if (f_compare_dynamic_partial_string(firewall_tool_s.string, main->data.buffer, firewall_tool_s.used, rule_objects->array[i]) == F_equal_to) { + if (rule_contents->array[i].used != 1) { + valid = F_false; + } + else { + if (f_compare_dynamic_partial_string(firewall_tool_iptables_s.string, main->data.buffer, firewall_tool_iptables_s.used, rule_contents->array[i].array[0]) == F_equal_to) { + tools[0] = (main->setting.flag & firewall_main_flag_ipv4_d) ? firewall_tool_iptables_s : f_string_empty_s; + tools[1] = f_string_empty_s; + } + else if (f_compare_dynamic_partial_string(firewall_tool_ip6tables_s.string, main->data.buffer, firewall_tool_ip6tables_s.used, rule_contents->array[i].array[0]) == F_equal_to) { + tools[0] = f_string_empty_s; + tools[1] = (main->setting.flag & firewall_main_flag_ipv6_d) ? firewall_tool_ip6tables_s : f_string_empty_s; + } + else if (f_compare_dynamic_partial_string(firewall_tool_ip46tables_s.string, main->data.buffer, firewall_tool_ip46tables_s.used, rule_contents->array[i].array[0]) == F_equal_to) { + tools[0] = (main->setting.flag & firewall_main_flag_ipv4_d) ? firewall_tool_iptables_s : f_string_empty_s; + tools[1] = (main->setting.flag & firewall_main_flag_ipv6_d) ? firewall_tool_ip6tables_s : f_string_empty_s; + } + else { + valid = F_false; + } + + if (valid) continue; + } + } + + // If the remaining rule does not match as firewall_rule_s, then it is an invalid rule. + else if (f_compare_dynamic_partial_string(firewall_rule_s.string, main->data.buffer, firewall_rule_s.used, rule_objects->array[i]) == F_equal_to_not) { + firewall_print_warning_object_invalid_missing_line(&main->program.warning, i, main->data.buffer, main->data.rule_objects.array[i]); + + continue; + } + + if (!valid) { + firewall_print_warning_content_invalid_missing_line(&main->program.warning, i, main->data.buffer, main->data.rule_objects.array[i]); + + continue; + } + + for (t = 0; t < 2; ++t) { + + if (macro_firewall_signal_check(&main->program, &main->setting.state)) return; + + if (!tools[t].used) continue; + + // First add the program name. + main->cache.arguments.used = 0; + + main->setting.state.status = f_memory_array_increase(firewall_allocation_small_d, sizeof(f_string_dynamic_t), (void **) &main->cache.arguments.array, &main->cache.arguments.used, &main->cache.arguments.size); + if (F_status_is_error(main->setting.state.status)) return; + + // Process the action when a non-none chain is specified. + if (chain != firewall_chain_none_e && action != firewall_action_none_e) { + main->setting.state.status = f_memory_array_increase(firewall_allocation_small_d, sizeof(f_string_dynamic_t), (void **) &main->cache.arguments.array, &main->cache.arguments.used, &main->cache.arguments.size); + if (F_status_is_error(main->setting.state.status)) return; + + main->cache.arguments.array[main->cache.arguments.used].used = 0; + + if (action == firewall_action_append_e) { + main->setting.state.status = f_string_dynamic_append(firewall_action_append_operation_s, &main->cache.arguments.array[main->cache.arguments.used]); + } + else if (action == firewall_action_insert_e) { + main->setting.state.status = f_string_dynamic_append(firewall_action_insert_operation_s, &main->cache.arguments.array[main->cache.arguments.used]); + } + else if (action == firewall_action_policy_e) { + main->setting.state.status = f_string_dynamic_append(firewall_action_policy_operation_s, &main->cache.arguments.array[main->cache.arguments.used]); + } + + if (F_status_is_error(main->setting.state.status)) return; + + if (action == firewall_action_append_e || action == firewall_action_insert_e || action == firewall_action_policy_e) { + ++main->cache.arguments.used; + + main->setting.state.status = f_memory_array_increase(firewall_allocation_small_d, sizeof(f_string_dynamic_t), (void **) &main->cache.arguments.array, &main->cache.arguments.used, &main->cache.arguments.size); + if (F_status_is_error(main->setting.state.status)) return; + + main->cache.arguments.array[main->cache.arguments.used].used = 0; + main->setting.state.status = F_data_not; + + // Process the chain, which is required by the action. + if (chain == firewall_chain_custom_e) { + main->setting.state.status = f_string_dynamic_append(main->setting.chains.array[main->data.chain_ids.array[main->data.chain]], &main->cache.arguments.array[main->cache.arguments.used]); + } + else if (chain == firewall_chain_forward_e) { + main->setting.state.status = f_string_dynamic_append(firewall_chain_forward_s, &main->cache.arguments.array[main->cache.arguments.used]); + } + else if (chain == firewall_chain_postrouting_e) { + main->setting.state.status = f_string_dynamic_append(firewall_chain_postrouting_s, &main->cache.arguments.array[main->cache.arguments.used]); + } + else if (chain == firewall_chain_prerouting_e) { + main->setting.state.status = f_string_dynamic_append(firewall_chain_prerouting_s, &main->cache.arguments.array[main->cache.arguments.used]); + } + else if (chain == firewall_chain_input_e) { + main->setting.state.status = f_string_dynamic_append(firewall_chain_input_s, &main->cache.arguments.array[main->cache.arguments.used]); + } + else if (chain == firewall_chain_output_e) { + main->setting.state.status = f_string_dynamic_append(firewall_chain_output_s, &main->cache.arguments.array[main->cache.arguments.used]); + } + + if (F_status_is_error(main->setting.state.status)) return; + + if (main->setting.state.status == F_data_not) { + main->setting.state.status = F_okay; + } + else { + ++main->cache.arguments.used; + } + } + } + + // Add the device if and only if a non-none direction is specified. + if (main->cache.device.used && (direction == firewall_direction_input_e || direction == firewall_direction_output_e)) { + if (f_compare_dynamic_partial_string(firewall_device_all_s.string, main->data.buffer, firewall_device_all_s.used, rule_contents->array[i].array[0]) == F_equal_to_not) { + main->setting.state.status = f_memory_array_increase(firewall_allocation_small_d, sizeof(f_string_dynamic_t), (void **) &main->cache.arguments.array, &main->cache.arguments.used, &main->cache.arguments.size); + if (F_status_is_error(main->setting.state.status)) return; + + main->cache.arguments.array[main->cache.arguments.used].used = 0; + + if (direction == firewall_direction_input_e) { + main->setting.state.status = f_string_dynamic_append(firewall_device_input_operation_s, &main->cache.arguments.array[main->cache.arguments.used]); + if (F_status_is_error(main->setting.state.status)) return; + + ++main->cache.arguments.used; + } + else if (direction == firewall_direction_output_e) { + main->setting.state.status = f_string_dynamic_append(firewall_device_output_operation_s, &main->cache.arguments.array[main->cache.arguments.used]); + if (F_status_is_error(main->setting.state.status)) return; + + ++main->cache.arguments.used; + } + } + + // Add the device. + if (main->cache.device.used) { + main->setting.state.status = f_memory_array_increase(firewall_allocation_small_d, sizeof(f_string_dynamic_t), (void **) &main->cache.arguments.array, &main->cache.arguments.used, &main->cache.arguments.size); + if (F_status_is_error(main->setting.state.status)) return; + + main->cache.arguments.array[main->cache.arguments.used].used = 0; + + main->setting.state.status = f_string_dynamic_append(main->cache.device, &main->cache.arguments.array[main->cache.arguments.used]); + if (F_status_is_error(main->setting.state.status)) return; + + ++main->cache.arguments.used; + } + } + + if (use_protocol) { + main->setting.state.status = f_memory_array_increase(firewall_allocation_small_d, sizeof(f_string_dynamic_t), (void **) &main->cache.arguments.array, &main->cache.arguments.used, &main->cache.arguments.size); + if (F_status_is_error(main->setting.state.status)) return; + + main->cache.arguments.array[main->cache.arguments.used].used = 0; + + main->setting.state.status = f_string_dynamic_append(firewall_protocol_operation_s, &main->cache.arguments.array[main->cache.arguments.used]); + if (F_status_is_error(main->setting.state.status)) return; + + ++main->cache.arguments.used; + + if (main->cache.protocol.used) { + main->setting.state.status = f_memory_array_increase(firewall_allocation_small_d, sizeof(f_string_dynamic_t), (void **) &main->cache.arguments.array, &main->cache.arguments.used, &main->cache.arguments.size); + if (F_status_is_error(main->setting.state.status)) return; + + main->cache.arguments.array[main->cache.arguments.used].used = 0; + + main->setting.state.status = f_string_dynamic_append(main->cache.protocol, &main->cache.arguments.array[main->cache.arguments.used]); + if (F_status_is_error(main->setting.state.status)) return; + + ++main->cache.arguments.used; + } + } + + // Last up is the "rule". + if ((!is_ip_list && rule_contents->array[i].used > 0) || (is_ip_list && rule_contents->array[i].used > 1)) { + at = 0; + + if (is_ip_list) { + + // Skip past the chain. + ++at; + + if (rule_contents->array[i].array[at].start <= rule_contents->array[i].array[at].stop) { + main->cache.ip_list.used = 0; + + main->setting.state.status = f_string_dynamic_partial_append(main->data.buffer, rule_contents->array[i].array[at], &main->cache.ip_list); + + if (F_status_is_error(main->setting.state.status)) { + + // Prevent the loop below from being processed. + at = rule_contents->array[i].used; + } + else { + ++at; + } + } + } + + main->setting.state.status = f_memory_array_increase_by(rule_contents->array[i].used, sizeof(f_string_dynamic_t), (void **) &main->cache.arguments.array, &main->cache.arguments.used, &main->cache.arguments.size); + if (F_status_is_error(main->setting.state.status)) return; + + for (; at < rule_contents->array[i].used; ++at) { + + if (macro_firewall_signal_check(&main->program, &main->setting.state)) return; + + if (rule_contents->array[i].array[at].start <= rule_contents->array[i].array[at].stop) { + main->cache.arguments.array[main->cache.arguments.used].used = 0; + + main->setting.state.status = f_string_dynamic_partial_append(main->data.buffer, rule_contents->array[i].array[at], &main->cache.arguments.array[main->cache.arguments.used]); + if (F_status_is_error(main->setting.state.status)) return; + + ++main->cache.arguments.used; + } + } // for + } + else { + firewall_print_warning_content_invalid_missing_line(&main->program.warning, i, main->data.buffer, main->data.rule_objects.array[i]); + + break; + } + + // Now execute the generated commands. + if (main->cache.arguments.used > 1) { + if (is_ip_list) { + main->cache.basic_objects.used = 0; + main->cache.basic_contents.used = 0; + main->cache.buffer.used = 0; + main->cache.delimits.used = 0; + main->cache.path_file_specific.used = 0; + + main->setting.state.status = f_string_dynamic_append(firewall_network_firewall_path_s, &main->cache.path_file_specific); + + if (F_status_is_error_not(main->setting.state.status)) { + main->setting.state.status = f_string_dynamic_append(main->cache.ip_list, &main->cache.path_file_specific); + } + + if (F_status_is_error(main->setting.state.status)) { + firewall_print_error(&main->program.error, F_status_debug_source_d); + + return; + } + + main->setting.state.status = f_file_open(main->cache.path_file_specific, 0, &main->cache.file); + + if (F_status_is_error(main->setting.state.status)) { + firewall_print_error_file(&main->program.error, F_status_debug_source_d, main->cache.path_file_specific, f_file_operation_open_s, fll_error_file_type_file_e); + + f_file_stream_close(&main->cache.file); + + return; + } + + main->setting.state.status = f_file_read(main->cache.file, &main->cache.buffer); + + f_file_stream_close(&main->cache.file); + + if (F_status_is_error(main->setting.state.status)) { + firewall_print_error_file(&main->program.error, F_status_debug_source_d, main->cache.path_file_specific, f_file_operation_read_s, fll_error_file_type_file_e); + + return; + } + + main->cache.delimits.used = 0; + + if (main->cache.buffer.used) { + main->data.range.start = 0; + main->data.range.stop = main->cache.buffer.used - 1; + } + else { + main->data.range.start = 1; + main->data.range.stop = 0; + } + + fll_fss_basic_read(main->cache.buffer, &main->data.range, &main->cache.basic_objects, &main->cache.basic_contents, 0, &main->cache.delimits, 0, &main->setting.state); + + if (F_status_is_error(main->setting.state.status)) { + if (F_status_set_fine(main->setting.state.status) == F_data_not_eos || F_status_set_fine(main->setting.state.status) == F_data_not || F_status_set_fine(main->setting.state.status) == F_data_not_stop) { + // Empty files are to be silently ignored. + } + else { + firewall_print_error_file(&main->program.error, F_status_debug_source_d, main->cache.path_file_specific, f_file_operation_read_s, fll_error_file_type_file_e); + + return; + } + } + + f_fss_apply_delimit(main->cache.delimits, &main->cache.buffer, &main->setting.state); + + if (F_status_is_error(main->setting.state.status)) { + firewall_print_error(&main->program.error, F_status_debug_source_d); + } + + if (F_status_is_error_not(main->setting.state.status)) { + main->setting.state.status = f_memory_array_increase_by(2, sizeof(f_string_dynamic_t), (void **) &main->cache.arguments.array, &main->cache.arguments.used, &main->cache.arguments.size); + + if (F_status_is_error(main->setting.state.status)) { + firewall_print_error(&main->program.error, F_status_debug_source_d); + + return; + } + + main->cache.arguments.array[main->cache.arguments.used].used = 0; + + main->setting.state.status = f_string_dynamic_append(ip_list_direction ? firewall_ip_list_destination_action_s : firewall_ip_list_source_action_s, &main->cache.arguments.array[main->cache.arguments.used]); + + if (F_status_is_error(main->setting.state.status)) { + firewall_print_error(&main->program.error, F_status_debug_source_d); + + return; + } + + ++main->cache.arguments.used; + + // The ip_list file contains objects and no content, all objects are what matter an nothing else. + for (at = 0; at < main->cache.basic_objects.used; ++at) { + + if (macro_firewall_signal_check(&main->program, &main->setting.state)) return; + + main->cache.arguments.array[main->cache.arguments.used].used = 0; + + main->setting.state.status = f_string_dynamic_partial_append(main->cache.buffer, main->cache.basic_objects.array[at], &main->cache.arguments.array[main->cache.arguments.used]); + + if (F_status_is_error(main->setting.state.status)) { + firewall_print_error(&main->program.error, F_status_debug_source_d); + + return; + } + + ++main->cache.arguments.used; + return_code = 0; + + firewall_print_debug_tool(&main->program.warning, tools[t], main->cache.arguments); + + main->setting.state.status = fll_execute_program(tools[t], main->cache.arguments, 0, 0, (void *) &return_code); + + if (main->setting.state.status == F_child) { + main->program.child = return_code; + + return; + } + + // Remove ip_argument from arguments string. + --main->cache.arguments.used; + + if (F_status_is_error(main->setting.state.status)) { + if (F_status_set_fine(main->setting.state.status) == F_failure) { + firewall_print_error_operation(&main->program.error, tools[t], main->cache.arguments); + } + else { + firewall_print_error(&main->program.error, F_status_debug_source_d); + } + + return; + } + else if (return_code) { + firewall_print_error_operation_return_code(&main->program.error, tools[t], main->cache.arguments, return_code); + } + } // for + + // Remove ip_list_action from arguments string. + --main->cache.arguments.used; + } + + if (F_status_set_fine(main->setting.state.status) == F_failure || F_status_set_fine(main->setting.state.status) == F_parameter) return; + } + else { + return_code = 0; + + firewall_print_debug_tool(&main->program.warning, tools[t], main->cache.arguments); + + main->setting.state.status = fll_execute_program(tools[t], main->cache.arguments, 0, 0, (void *) &return_code); + + if (main->setting.state.status == F_child) { + main->program.child = return_code; + + return; + } + + if (F_status_is_error(main->setting.state.status)) { + if (F_status_set_fine(main->setting.state.status) == F_failure) { + firewall_print_error_operation(&main->program.error, tools[t], main->cache.arguments); + } + else { + firewall_print_error(&main->program.error, F_status_debug_source_d); + } + + return; + } + else if (return_code) { + firewall_print_error_operation_return_code(&main->program.error, tools[t], main->cache.arguments, return_code); + } + } + } + } // for + } // for + + main->setting.state.status = F_okay; + } +#endif // _di_firewall_operate_process_rules_perform_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/main/operate/process.h b/sources/c/main/operate/process.h new file mode 100644 index 0000000..241e88c --- /dev/null +++ b/sources/c/main/operate/process.h @@ -0,0 +1,42 @@ +/** + * FLL - Level 3 + * + * Project: Firewall + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Provides the operate process functionality. + * + * This is auto-included and should not need to be explicitly included. + */ +#ifndef _firewall_operate_process_h +#define _firewall_operate_process_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Perforrm the loaded firewall rules. + * + * @param main + * The main program and setting data. + * + * This alters main.setting.state.status: + * F_okay on success. + * + * F_interrupt (with error bit) on interrupt signal received. + * + * Errors (with error bit) from: () + * + * @see () + */ +#ifndef _di_firewall_operate_process_rules_ + extern void firewall_operate_process_rules(firewall_main_t * const main); +#endif // _di_firewall_operate_process_rules_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _firewall_operate_process_h diff --git a/sources/c/main/operate/rules.c b/sources/c/main/operate/rules.c new file mode 100644 index 0000000..c049efd --- /dev/null +++ b/sources/c/main/operate/rules.c @@ -0,0 +1,28 @@ +#include "../firewall.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_firewall_operate_rules_ + void firewall_operate_rules(firewall_main_t * const main) { + + if (!main || F_status_is_error_not(main->setting.state.status) && main->setting.state.status == F_child) return; + + firewall_operate_process_rules(main); + + if (F_status_is_error(main->setting.state.status)) { + if (F_status_set_fine(main->setting.state.status) != F_failure && F_status_set_fine(main->setting.state.status) != F_interrupt) { + firewall_print_error_unhandled(&main->program.error, F_status_debug_source_d, f_string_empty_s); + } + + return; + } + + main->setting.state.status = F_okay; + } +#endif // _di_firewall_operate_rules_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/main/operate/rules.h b/sources/c/main/operate/rules.h new file mode 100644 index 0000000..0d77086 --- /dev/null +++ b/sources/c/main/operate/rules.h @@ -0,0 +1,46 @@ +/** + * FLL - Level 3 + * + * Project: Firewall + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Provides the operate rules functionality. + * + * This is auto-included and should not need to be explicitly included. + */ +#ifndef _firewall_operate_rules_h +#define _firewall_operate_rules_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Operate the rules. + * + * @param main + * The main program and setting data. + * + * This alters main.setting.state.status: + * F_okay on success. + * + * F_interrupt (with error bit) on interrupt signal received. + * + * Errors (with error bit) from: f_fss_apply_delimit() + * Errors (with error bit) from: firewall_operate_process_rules() + * Errors (with error bit) from: fll_fss_extended_read() + * + * @see f_fss_apply_delimit() + * @see firewall_operate_process_rules() + * @see fll_fss_extended_read() + */ +#ifndef _di_firewall_operate_rules_ + extern void firewall_operate_rules(firewall_main_t * const main); +#endif // _di_firewall_operate_rules_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _firewall_operate_rules_h diff --git a/sources/c/main/operate/show.c b/sources/c/main/operate/show.c new file mode 100644 index 0000000..fdaf248 --- /dev/null +++ b/sources/c/main/operate/show.c @@ -0,0 +1,128 @@ +#include "../firewall.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_firewall_operate_show_ + void firewall_operate_show(firewall_main_t * const main) { + + if (!main) return; + + int return_code = 0; + + f_string_statics_t parameters = f_string_statics_t_initialize; + parameters.used = 6; + + f_string_static_t show_nats[] = { + firewall_show_parameter_exact_s, + firewall_show_parameter_verbose_s, + firewall_show_parameter_table_s, + firewall_show_nat_s, + firewall_show_parameter_numeric_s, + firewall_show_parameter_list_s, + }; + + f_string_static_t show_mangles[] = { + firewall_show_parameter_exact_s, + firewall_show_parameter_verbose_s, + firewall_show_parameter_table_s, + firewall_show_mangle_s, + firewall_show_parameter_numeric_s, + firewall_show_parameter_list_s, + }; + + f_string_static_t show_filters[] = { + firewall_show_parameter_exact_s, + firewall_show_parameter_verbose_s, + firewall_show_parameter_numeric_s, + firewall_show_parameter_list_s, + }; + + f_string_static_t * const show_arrays[] = { + show_nats, + show_mangles, + show_filters, + }; + + const f_number_unsigned_t show_lengths[] = { + 6, + 6, + 4, + }; + + const f_string_static_t show_lefts[] = { + firewall_print_show_bars_27_s, + firewall_print_show_bars_26_s, + firewall_print_show_bars_26_s, + }; + + const f_string_static_t show_headers[] = { + firewall_print_show_nat_s, + firewall_print_show_mangle_s, + firewall_print_show_filter_s, + }; + + const f_string_static_t show_rights[] = { + firewall_print_show_bars_28_s, + firewall_print_show_bars_26_s, + firewall_print_show_bars_26_s, + }; + + const uint16_t show_flags[] = { + firewall_main_flag_operation_show_nat_d, + firewall_main_flag_operation_show_mangle_d, + firewall_main_flag_operation_show_filter_d, + }; + + const f_string_static_t tools[2] = { main->setting.flag & firewall_main_flag_ipv4_d ? firewall_tool_iptables_s : f_string_empty_s, main->setting.flag & firewall_main_flag_ipv6_d ? firewall_tool_ip6tables_s : f_string_empty_s }; + + uint8_t i = 0; + uint8_t t = 0; + + for (; t < 2; ++t) { + + if (!tools[t].used) continue; + + for (i = 0; i < 3; ++i) { + + if (!show_flags[i]) continue; + + parameters.array = show_arrays[i]; + parameters.used = show_lengths[i]; + return_code = 0; + + // A newline should be printed before each inner message header, but not the first. + if (i) { + f_print_dynamic_raw(f_string_eol_s, main->program.output.to); + } + + firewall_print_message_show_header(&main->program.output, show_lefts[i], show_headers[i], show_rights[i], t); + + main->setting.state.status = fll_execute_program(tools[t], parameters, 0, 0, (void *) &return_code); + + if (main->setting.state.status == F_child) { + main->program.child = return_code; + + return; + } + + if (F_status_is_error(main->setting.state.status)) { + firewall_print_error_operation(&main->program.error, tools[t], parameters); + + return; + } + + if (return_code) { + firewall_print_error_operation_return_code(&main->program.error, tools[t], main->cache.arguments, return_code); + } + } // for + } // for + + main->setting.state.status = F_okay; + } +#endif // _di_firewall_operate_show_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/main/operate/show.h b/sources/c/main/operate/show.h new file mode 100644 index 0000000..33d4a81 --- /dev/null +++ b/sources/c/main/operate/show.h @@ -0,0 +1,45 @@ +/** + * FLL - Level 3 + * + * Project: Firewall + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Provides the operate show functionality. + * + * This is auto-included and should not need to be explicitly included. + */ +#ifndef _firewall_operate_show_h +#define _firewall_operate_show_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Perform the firewall show operation. + * + * @param main + * The main program and setting data. + * + * This alters main.setting.state.status: + * F_okay on success. + * F_child on child process exiting. + * + * F_interrupt (with error bit) on interrupt signal received. + * + * Errors (with error bit) from: fll_execute_program() + * Errors (with error bit) from: fll_print_dynamic_raw() + * + * @see fll_execute_program() + * @see fll_print_dynamic_raw() + */ +#ifndef _di_firewall_operate_show_ + extern void firewall_operate_show(firewall_main_t * const main); +#endif // _di_firewall_operate_show_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _firewall_operate_show_h diff --git a/sources/c/main/print/debug.c b/sources/c/main/print/debug.c new file mode 100644 index 0000000..c380486 --- /dev/null +++ b/sources/c/main/print/debug.c @@ -0,0 +1,31 @@ +#include "../firewall.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_firewall_print_debug_tool_ + f_status_t firewall_print_debug_tool(fl_print_t * const print, const f_string_static_t tool, const f_string_statics_t arguments) { + + if (!print) return F_status_set_error(F_output_not); + if (print->verbosity != f_console_verbosity_debug_e) return F_output_not; + + f_file_stream_lock(print->to); + + fl_print_format("%[%Q", print->to, print->context, tool); + + for (f_number_unsigned_t i = 0; i < arguments.used; ++i) { + fl_print_format(" %Q", print->to, arguments.array[i]); + } // for + + fl_print_format("%]%r", print->to, print->context, f_string_eol_s); + + f_file_stream_unlock(print->to); + + return F_okay; + } +#endif // _di_firewall_print_debug_tool_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/main/print/debug.h b/sources/c/main/print/debug.h new file mode 100644 index 0000000..fd45e4f --- /dev/null +++ b/sources/c/main/print/debug.h @@ -0,0 +1,46 @@ +/** + * FLL - Level 3 + * + * Project: Firewall + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Provides the print debug functionality. + * + * This is auto-included and should not need to be explicitly included. + */ +#ifndef _firewall_print_debug_h +#define _firewall_print_debug_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Print debug information about tool execution. + * + * @param print + * The output structure to print to. + * + * This does not alter print.custom.setting.state.status. + * @param tool + * The name of the function associated with the error. + * @param arguments + * The name of the file, if this error is assocaited with a file. + * Otherwise, set file.used to 0 to not have an file related error message. + * + * @return + * F_okay on success. + * F_output_not on success, but no printing is performed. + * + * F_output_not (with error bit) if setting is NULL. + */ +#ifndef _di_firewall_print_debug_tool_ + extern f_status_t firewall_print_debug_tool(fl_print_t * const print, const f_string_static_t tool, const f_string_statics_t arguments); +#endif // _di_firewall_print_debug_tool_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _firewall_print_debug_h diff --git a/sources/c/main/print/error.c b/sources/c/main/print/error.c new file mode 100644 index 0000000..d630150 --- /dev/null +++ b/sources/c/main/print/error.c @@ -0,0 +1,185 @@ +#include "../firewall.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_firewall_print_error_ + f_status_t firewall_print_error(fl_print_t * const print, const f_string_t debug) { + + if (!print || !print->custom) return F_status_set_error(F_output_not); + if (print->verbosity < f_console_verbosity_error_e) return F_output_not; + + fll_error_print(print, F_status_set_fine(((firewall_main_t *) print->custom)->setting.state.status), debug, fll_error_file_flag_fallback_e); + + return F_okay; + } +#endif // _di_firewall_print_error_ + +#ifndef _di_firewall_print_error_file_ + f_status_t firewall_print_error_file(fl_print_t * const print, const f_string_t debug, const f_string_static_t name, const f_string_static_t operation, const uint8_t type) { + + if (!print || !print->custom) return F_status_set_error(F_output_not); + if (print->verbosity < f_console_verbosity_error_e) return F_output_not; + + fll_error_file_print(print, F_status_set_fine(((firewall_main_t *) print->custom)->setting.state.status), debug, fll_error_file_flag_fallback_e, name, operation, type); + + return F_okay; + } +#endif // _di_firewall_print_error_file_ + +#ifndef _di_firewall_print_error_file_empty_ + f_status_t firewall_print_error_file_empty(fl_print_t * const print, const f_string_static_t file) { + + if (!print) return F_status_set_error(F_output_not); + if (print->verbosity < f_console_verbosity_error_e) return F_output_not; + + f_file_stream_lock(print->to); + + fl_print_format("%[%QNo relevant data is found within the file '%]", print->to, print->context, print->prefix, print->context); + fl_print_format(f_string_format_Q_single_s.string, print->to, print->notable, file, print->notable); + fl_print_format(f_string_format_sentence_end_single_quote_s.string, print->to, print->context, print->context, f_string_eol_s); + + f_file_stream_unlock(print->to); + + return F_okay; + } +#endif // _di_firewall_print_error_file_empty_ + +#ifndef _di_firewall_print_error_network_device_none_ + f_status_t firewall_print_error_network_device_none(fl_print_t * const print) { + + if (!print) return F_status_set_error(F_output_not); + if (print->verbosity < f_console_verbosity_error_e) return F_output_not; + + fll_print_format("%[%QCould not find any network devices.%]%r", print->to, print->context, print->prefix, print->context, f_string_eol_s); + + return F_okay; + } +#endif // _di_firewall_print_error_network_device_none_ + +#ifndef _di_firewall_print_error_operation_ + f_status_t firewall_print_error_operation(fl_print_t * const print, const f_string_static_t tool, const f_string_statics_t arguments) { + + if (!print || !print->custom) return F_status_set_error(F_output_not); + if (print->verbosity < f_console_verbosity_error_e) return F_output_not; + + firewall_main_t * const main = (firewall_main_t *) print->custom; + + f_file_stream_lock(print->to); + + if (F_status_set_fine(main->setting.state.status) == F_memory_not) { + fl_print_format("%[%QOut of memory while performing requested %r operation '%]", print->to, print->context, print->prefix, tool, print->context); + } + else { + fl_print_format("%[%QFailed to perform requested %r operation '%]", print->to, print->context, print->prefix, tool, print->context); + } + + fl_print_format("%[%Q", print->to, print->set->notable, tool); + + for (f_number_unsigned_t i = 0; i < arguments.used; ++i) { + fl_print_format(" %Q", print->to, arguments.array[i]); + } // for + + fl_print_format("%]%[', error code is%] ", print->to, print->set->notable, print->context, print->context); + fl_print_format(f_string_format_ui_single_s.string, print->to, print->set->notable, F_status_set_fine(main->setting.state.status), print->set->notable); + fl_print_format(f_string_format_sentence_end_single_s.string, print->to, print->context, print->context, f_string_eol_s); + + f_file_stream_unlock(print->to); + + return F_okay; + } +#endif // _di_firewall_print_error_operation_ + +#ifndef _di_firewall_print_error_operation_files_missing_ + f_status_t firewall_print_error_operation_files_missing(fl_print_t * const print, const f_string_static_t operation, const f_string_static_t file) { + + if (!print || !print->custom) return F_status_set_error(F_output_not); + if (print->verbosity == f_console_verbosity_quiet_e) return F_output_not; + + f_file_stream_lock(print->to); + + fl_print_format("%[%QFailed to perform%] ", print->to, print->context, print->prefix); + fl_print_format(f_string_format_Q_single_s.string, print->to, print->notable, operation, print->notable); + fl_print_format(" %[request because the%] ", print->to, print->context, print->prefix, print->context); + fl_print_format(f_string_format_Q_single_s.string, print->to, print->notable, operation, print->notable); + fl_print_format(" %[instructions are missing from '%]", print->to, print->set->error, print->set->error); + fl_print_format(f_string_format_Q_single_s.string, print->to, print->notable, file, print->notable); + fl_print_format(f_string_format_sentence_end_single_quote_s.string, print->to, print->set->error, print->set->error, f_string_eol_s); + + f_file_stream_unlock(print->to); + + return F_okay; + } +#endif // _di_firewall_print_error_operation_files_missing_ + +#ifndef _di_firewall_print_error_operation_return_code_ + f_status_t firewall_print_error_operation_return_code(fl_print_t * const print, const f_string_static_t tool, const f_string_statics_t arguments, const int return_code) { + + if (!print || !print->custom) return F_status_set_error(F_output_not); + if (print->verbosity < f_console_verbosity_error_e) return F_output_not; + + f_file_stream_lock(print->to); + + fl_print_format("%[%QThe operation '%]", print->to, print->context, print->prefix, tool, print->context); + fl_print_format("%[%Q", print->to, print->set->notable, tool); + + for (f_number_unsigned_t i = 0; i < arguments.used; ++i) { + fl_print_format(" %Q", print->to, arguments.array[i]); + } // for + + fl_print_format("%]%[' returned with code of%] ", print->to, print->set->notable, print->context, print->context); + fl_print_format(f_string_format_i_single_s.string, print->to, print->set->notable, return_code, print->set->notable); + fl_print_format(f_string_format_sentence_end_single_s.string, print->to, print->context, print->context, f_string_eol_s); + + f_file_stream_unlock(print->to); + + return F_okay; + } +#endif // _di_firewall_print_error_operation_return_code_ + +#ifndef _di_firewall_print_error_operation_specified_not_ + f_status_t firewall_print_error_operation_specified_not(fl_print_t * const print) { + + if (!print) return F_status_set_error(F_output_not); + if (print->verbosity < f_console_verbosity_error_e) return F_output_not; + + fll_print_format("%[%QNo operation is given.%]%r", print->to, print->context, print->prefix, print->context, f_string_eol_s); + + return F_okay; + } +#endif // _di_firewall_print_error_operation_specified_not_ + +#ifndef _di_firewall_print_error_unhandled_ + f_status_t firewall_print_error_unhandled(fl_print_t * const print, const f_string_t debug, const f_string_static_t file) { + + if (!print || !print->custom) return F_status_set_error(F_output_not); + if (print->verbosity < f_console_verbosity_error_e) return F_output_not; + + firewall_main_t * const main = (firewall_main_t *) print->custom; + + f_file_stream_lock(print->to); + + fl_print_format("%[%QAn unhandled error (%]", print->to, f_string_eol_s, print->context, print->prefix, print->context); + fl_print_format(f_string_format_ui_single_s.string, print->to, print->notable, F_status_set_fine(main->setting.state.status), print->notable); + fl_print_format("%[) has occurred while calling%] ", print->to, print->context, print->prefix, print->context); + fl_print_format(f_string_format_S_single_s.string, print->to, print->notable, debug, print->notable); + + if (file.used) { + fl_print_format("%[() for the file%] ", print->to, print->context, print->prefix, print->context); + fl_print_format(f_string_format_Q_single_s.string, print->to, print->notable, file, print->notable); + fl_print_format(f_string_format_sentence_end_single_s.string, print->to, print->context, print->context, f_string_eol_s); + } + else { + fl_print_format("%[().%]%r", print->to, print->context, print->context, f_string_eol_s); + } + + f_file_stream_unlock(print->to); + + return F_okay; + } +#endif // _di_firewall_print_error_unhandled_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/main/print/error.h b/sources/c/main/print/error.h new file mode 100644 index 0000000..c39b4d8 --- /dev/null +++ b/sources/c/main/print/error.h @@ -0,0 +1,237 @@ +/** + * FLL - Level 3 + * + * Project: Firewall + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Provides the print error functionality. + * + * This is auto-included and should not need to be explicitly included. + */ +#ifndef _firewall_print_error_h +#define _firewall_print_error_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Print generic error message regarding a function failing in some way. + * + * @param print + * The output structure to print to. + * + * This does not alter print.custom.setting.state.status. + * @param debug + * (optional) The debug details, such as file, line number, and function. + * + * Set to NULL to disable. + * + * @return + * F_okay on success. + * F_output_not on success, but no printing is performed. + * + * F_output_not (with error bit) if setting is NULL. + * + * @see fll_error_print() + */ +#ifndef _di_firewall_print_error_ + extern f_status_t firewall_print_error(fl_print_t * const print, const f_string_t debug); +#endif // _di_firewall_print_error_ + +/** + * Print file related error or warning messages. + * + * @param print + * The output structure to print to. + * + * This does not alter print.custom.setting.state.status. + * @param debug + * (optional) The debug details, such as file, line number, and function. + * + * Set to NULL to disable. + * @param name + * The name of the file or directory. + * @param operation + * The operation that fails, such as 'create' or 'access'. + * @param type + * A valid file type code from the fll_error_file_type enum. + * + * @return + * F_okay on success. + * F_output_not on success, but no printing is performed. + * + * F_output_not (with error bit) if setting is NULL. + * + * @see fll_error_file_print() + */ +#ifndef _di_firewall_print_error_file_ + extern f_status_t firewall_print_error_file(fl_print_t * const print, const f_string_t debug, const f_string_static_t name, const f_string_static_t operation, const uint8_t type); +#endif // _di_firewall_print_error_file_ + +/** + * Print file related error message regarding that there is no relevant data in the file. + * + * The file is effectively empty but could have comments or other non-valid (aka non-Object) data. + * + * @param print + * The output structure to print to. + * + * This does not alter print.custom.setting.state.status. + * @param debug + * (optional) The debug details, such as file, line number, and function. + * + * Set to NULL to disable. + * + * @return + * F_okay on success. + * F_output_not on success, but no printing is performed. + * + * F_output_not (with error bit) if setting is NULL. + * + * @see fll_error_file_print() + */ +#ifndef _di_firewall_print_error_file_empty_ + extern f_status_t firewall_print_error_file_empty(fl_print_t * const print, const f_string_static_t file); +#endif // _di_firewall_print_error_file_empty_ + +/** + * Print error message regarding being unable to find any devices. + * + * @param print + * The output structure to print to. + * + * This does not alter print.custom.setting.state.status. + * + * @return + * F_okay on success. + * F_output_not on success, but no printing is performed. + * + * F_output_not (with error bit) if setting is NULL. + * + * @see fll_error_print() + */ +#ifndef _di_firewall_print_error_network_device_none_ + extern f_status_t firewall_print_error_network_device_none(fl_print_t * const print); +#endif // _di_firewall_print_error_network_device_none_ + +/** + * Print an error about the given operation failed. + * + * @param print + * The output structure to print to. + * + * This does not alter print.custom.setting.state.status. + * @param tool + * The tool, such as iptables, that failed. + * @param arguments + * The arguments passed to the tool. + * + * @return + * F_okay on success. + * F_output_not on success, but no printing is performed. + * + * F_output_not (with error bit) if setting is NULL. + */ +#ifndef _di_firewall_print_error_operation_ + extern f_status_t firewall_print_error_operation(fl_print_t * const print, const f_string_static_t tool, const f_string_statics_t arguments); +#endif // _di_firewall_print_error_operation_ + +/** + * Print an error about the operation setting missing from the file. + * + * @param print + * The output structure to print to. + * + * This does not alter print.custom.setting.state.status. + * @param operation + * The operation setting that is missing from the file. + * This is also the name of the operation itself. + * @param file + * The file that is missing the operation. + * + * @return + * F_okay on success. + * F_output_not on success, but no printing is performed. + * + * F_output_not (with error bit) if setting is NULL. + */ +#ifndef _di_firewall_print_error_operation_files_missing_ + extern f_status_t firewall_print_error_operation_files_missing(fl_print_t * const print, const f_string_static_t operation, const f_string_static_t file); +#endif // _di_firewall_print_error_operation_files_missing_ + +/** + * Print an error about the given operation failed according to the given return code. + * + * @param print + * The output structure to print to. + * + * This does not alter print.custom.setting.state.status. + * @param tool + * The tool, such as iptables, that failed. + * @param arguments + * The arguments passed to the tool. + * @param return_code + * The code returned by the tool. + * + * @return + * F_okay on success. + * F_output_not on success, but no printing is performed. + * + * F_output_not (with error bit) if setting is NULL. + */ +#ifndef _di_firewall_print_error_operation_return_code_ + extern f_status_t firewall_print_error_operation_return_code(fl_print_t * const print, const f_string_static_t tool, const f_string_statics_t arguments, const int return_code); +#endif // _di_firewall_print_error_operation_return_code_ + +/** + * Print generic error message regarding a function failing in some way. + * + * @param print + * The output structure to print to. + * + * This does not alter print.custom.setting.state.status. + * + * @return + * F_okay on success. + * F_output_not on success, but no printing is performed. + * + * F_output_not (with error bit) if setting is NULL. + * + * @see fll_error_print() + */ +#ifndef _di_firewall_print_error_operation_specified_not_ + extern f_status_t firewall_print_error_operation_specified_not(fl_print_t * const print); +#endif // _di_firewall_print_error_operation_specified_not_ + +/** + * Print an unhandled error for the given function. + * + * @param print + * The output structure to print to. + * + * This does not alter print.custom.setting.state.status. + * @param debug + * (optional) The debug details, such as file, line number, and function. + * + * Set to NULL to disable. + * @param file + * The name of the file, if this error is assocaited with a file. + * Otherwise, set file.used to 0 to not have an file related error message. + * + * @return + * F_okay on success. + * F_output_not on success, but no printing is performed. + * + * F_output_not (with error bit) if setting is NULL. + */ +#ifndef _di_firewall_print_error_unhandled_ + extern f_status_t firewall_print_error_unhandled(fl_print_t * const print, const f_string_t debug, const f_string_static_t file); +#endif // _di_firewall_print_error_unhandled_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _firewall_print_error_h diff --git a/sources/c/main/print/message.c b/sources/c/main/print/message.c new file mode 100644 index 0000000..3e5c5c1 --- /dev/null +++ b/sources/c/main/print/message.c @@ -0,0 +1,72 @@ +#include "../firewall.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_firewall_print_message_help_ + f_status_t firewall_print_message_help(fl_print_t * const print) { + + if (!print || !print->custom) return F_status_set_error(F_output_not); + + f_file_stream_lock(print->to); + + fll_program_print_help_header(print, firewall_program_name_long_s, firewall_program_version_s); + + fll_program_print_help_option_standard(print); + + f_print_dynamic_raw(f_string_eol_s, print->to); + + fll_program_print_help_option_short(print, firewall_short_4_s, f_console_symbol_short_normal_s, "Explicitly use IPv4 for show and rules to use iptables."); + fll_program_print_help_option_short(print, firewall_short_6_s, f_console_symbol_short_normal_s, "Explicitly use IPv6 and rules to use ip6tables."); + + f_print_dynamic_raw(f_string_eol_s, print->to); + + fll_program_print_help_operations(print); + + fll_program_print_help_option_other(print, firewall_operation_lock_s, " Switch to rules intended to prevent all communication."); + fll_program_print_help_option_other(print, firewall_operation_restart_s, "Turn off and then turn on the firewall."); + fll_program_print_help_option_other(print, firewall_operation_show_s, " Show the active firewall settings."); + fll_program_print_help_option_other(print, firewall_operation_start_s, " Turn on the firewall."); + fll_program_print_help_option_other(print, firewall_operation_stop_s, " Turn off the firewall."); + + f_print_dynamic_raw(f_string_eol_s, print->to); + + fll_program_print_help_usage(print, firewall_program_name_s, firewall_program_help_parameters_s); + + f_file_stream_flush(print->to); + f_file_stream_unlock(print->to); + + return F_okay; + } +#endif // _di_firewall_print_message_help_ + +#ifndef _di_firewall_print_message_show_header_ + f_status_t firewall_print_message_show_header(fl_print_t * const print, const f_string_static_t left, const f_string_static_t header, const f_string_static_t right, const uint8_t ipv6) { + + if (!print) return F_status_set_error(F_output_not); + + f_file_stream_lock(print->to); + + if (left.used) { + fl_print_format("%[%Q%] ", print->to, print->set->standout, left, print->set->standout); + } + + fll_print_format("%[%Q (%Q)%]", print->to, print->set->title, header, ipv6 ? firewall_print_show_ipv6_s: firewall_print_show_ipv4_s, print->set->title, f_string_eol_s); + + if (left.used) { + fl_print_format(" %[%Q%]", print->to, print->set->standout, right, print->set->standout); + } + + f_print_dynamic_raw(f_string_eol_s, print->to); + + f_file_stream_flush(print->to); + f_file_stream_unlock(print->to); + + return F_okay; + } +#endif // _di_firewall_print_message_show_header_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/main/print/message.h b/sources/c/main/print/message.h new file mode 100644 index 0000000..50afb1c --- /dev/null +++ b/sources/c/main/print/message.h @@ -0,0 +1,88 @@ +/** + * FLL - Level 3 + * + * Project: Firewall + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Provides the print message functionality. + * + * This is auto-included and should not need to be explicitly included. + */ +#ifndef _firewall_print_message_h +#define _firewall_print_message_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Print help. + * + * @param print + * The output structure to print to. + * + * This does not alter print.custom.setting.state.status. + * + * @return + * F_okay on success. + * F_output_not on success, but no printing is performed. + * + * F_output_not (with error bit) if setting is NULL. + * + * @see f_file_stream_flush() + * @see f_file_stream_lock() + * @see f_file_stream_unlock() + * @see f_print_dynamic_raw() + * @see fl_print_format() + * + * @see fll_program_print_help_header() + * @see fll_program_print_help_option() + * @see fll_program_print_help_option_standard() + * @see fll_program_print_help_usage() + */ +#ifndef _di_firewall_print_message_help_ + extern f_status_t firewall_print_message_help(fl_print_t * const print); +#endif // _di_firewall_print_message_help_ + +/** + * Print show option header. + * + * @param print + * The output structure to print to. + * + * This does not alter print.custom.setting.state.status. + * @param left + * The option to show on the left side of the header text. + * The left.used may be 0. + * @param header + * The header text. + * The header.used should not be 0. + * @param right + * The option to show on the right side of the header text. + * The right.used may be 0. + * @param ipv6 + * If TRUE, then print IPv6 string. + * If FALSE, then print IPv4 string. + * + * @return + * F_okay on success. + * F_output_not on success, but no printing is performed. + * + * F_output_not (with error bit) if setting is NULL. + * + * @see f_file_stream_flush() + * @see f_file_stream_lock() + * @see f_file_stream_unlock() + * @see f_print_dynamic_raw() + * @see fl_print_format() + */ +#ifndef _di_firewall_print_message_show_header_ + extern f_status_t firewall_print_message_show_header(fl_print_t * const print, const f_string_static_t left, const f_string_static_t header, const f_string_static_t right, const uint8_t ipv6); +#endif // _di_firewall_print_message_show_header_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _firewall_print_message_h diff --git a/sources/c/main/print/warning.c b/sources/c/main/print/warning.c new file mode 100644 index 0000000..361f6e1 --- /dev/null +++ b/sources/c/main/print/warning.c @@ -0,0 +1,138 @@ +#include "../firewall.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _di_firewall_print_warning_chain_meaningless_line_ + f_status_t firewall_print_warning_chain_meaningless_line(fl_print_t * const print, const f_number_unsigned_t line) { + + if (!print || !print->custom) return F_status_set_error(F_output_not); + if (print->verbosity < f_console_verbosity_verbose_e) return F_output_not; + + firewall_main_t * const main = (firewall_main_t *) print->custom; + + f_file_stream_lock(print->to); + + fl_print_format("%[%QAt line%] ", print->to, print->context, print->prefix, print->context); + fl_print_format(f_string_format_un_single_s.string, print->to, print->notable, line, print->notable); + + if (main->data.file.used && main->data.file.string) { + fl_print_format(" %[of '%]", print->to, print->context, print->prefix, print->context); + fl_print_format(f_string_format_Q_single_s.string, print->to, print->notable, main->data.file, print->notable); + fl_print_format("%[' ", print->to, print->context); + } + else { + fl_print_format(" %[", print->to, print->context); + } + + fl_print_format("the chain option is meaningless inside of a custom chain%]%r", print->to, print->context, f_string_eol_s); + + f_file_stream_unlock(print->to); + f_file_stream_flush(print->to); + + return F_okay; + } +#endif // _di_firewall_print_warning_chain_meaningless_line_ + +#ifndef _di_firewall_print_warning_content_invalid_missing_line_ + f_status_t firewall_print_warning_content_invalid_missing_line(fl_print_t * const print, const f_number_unsigned_t line, const f_string_static_t buffer, const f_range_t range) { + + if (!print || !print->custom) return F_status_set_error(F_output_not); + if (print->verbosity < f_console_verbosity_verbose_e) return F_output_not; + + firewall_main_t * const main = (firewall_main_t *) print->custom; + + f_file_stream_lock(print->to); + + fl_print_format("%[%QAt line%] ", print->to, print->context, print->prefix, print->context); + + if (main->data.file.used && main->data.file.string) { + fl_print_format(" %[of '%]", print->to, print->context, print->prefix, print->context); + fl_print_format(f_string_format_Q_single_s.string, print->to, print->notable, main->data.file, print->notable); + fl_print_format("%[' ", print->to, print->context); + } + else { + fl_print_format(" %[", print->to, print->context); + } + + fl_print_format(f_string_format_un_single_s.string, print->to, print->notable, line, print->notable); + fl_print_format(" %[the object '%]", print->to, print->context, print->prefix, print->context); + fl_print_format(f_string_format_Q_range_single_s.string, print->to, print->notable, buffer, range, print->notable); + + if (range.start > range.stop) { + fl_print_format("%[' has no content.%]%r", print->to, print->context, print->context, f_string_eol_s); + } + else { + fl_print_format("%[' is invalid.%]%r", print->to, print->context, print->context, f_string_eol_s); + } + + f_file_stream_unlock(print->to); + f_file_stream_flush(print->to); + + return F_okay; + } +#endif // _di_firewall_print_warning_content_invalid_missing_line_ + +#ifndef _di_firewall_print_warning_object_invalid_missing_line_ + f_status_t firewall_print_warning_object_invalid_missing_line(fl_print_t * const print, const f_number_unsigned_t line, const f_string_static_t buffer, const f_range_t range) { + + if (!print || !print->custom) return F_status_set_error(F_output_not); + if (print->verbosity < f_console_verbosity_verbose_e) return F_output_not; + + firewall_main_t * const main = (firewall_main_t *) print->custom; + + f_file_stream_lock(print->to); + + fl_print_format("%[%QAt line%] ", print->to, print->context, print->prefix, print->context); + fl_print_format(f_string_format_un_single_s.string, print->to, print->notable, line, print->notable); + + if (main->data.file.used && main->data.file.string) { + fl_print_format(" %[of '%]", print->to, print->context, print->prefix, print->context); + fl_print_format(f_string_format_Q_single_s.string, print->to, print->notable, main->data.file, print->notable); + fl_print_format("%[' ", print->to, print->context); + } + else { + fl_print_format(" %[", print->to, print->context); + } + + if (range.start > range.stop) { + fl_print_format(" %[the object is missing.%]%r", print->to, print->context, print->context, f_string_eol_s); + } + else { + fl_print_format(" %[the object '%]", print->to, print->context, print->prefix, print->context); + fl_print_format(f_string_format_Q_range_single_s.string, print->to, print->notable, buffer, range, print->notable); + fl_print_format("%[' is invalid.%]%r", print->to, print->context, print->context, f_string_eol_s); + } + + f_file_stream_unlock(print->to); + f_file_stream_flush(print->to); + + return F_okay; + } +#endif // _di_firewall_print_warning_object_invalid_missing_line_ + +#ifndef _di_firewall_print_warning_show_option_unknown_ + f_status_t firewall_print_warning_show_option_unknown(fl_print_t * const print, const f_string_static_t option) { + + if (!print) return F_status_set_error(F_output_not); + if (print->verbosity < f_console_verbosity_verbose_e) return F_output_not; + + f_file_stream_lock(print->to); + + fl_print_format("%[%QThe%] ", print->to, print->context, print->prefix, print->context); + fl_print_format(firewall_operation_show_s.string, print->to, print->notable, option, print->notable); + fl_print_format(" %[option '%]", print->to, print->context, print->prefix, print->context); + fl_print_format(f_string_format_Q_single_s.string, print->to, print->notable, option, print->notable); + fl_print_format("%[' is not known.%]%r", print->to, print->context, print->context, f_string_eol_s); + + f_file_stream_unlock(print->to); + f_file_stream_flush(print->to); + + return F_okay; + } +#endif // _di_firewall_print_warning_show_option_unknown_ + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/main/print/warning.h b/sources/c/main/print/warning.h new file mode 100644 index 0000000..318e89b --- /dev/null +++ b/sources/c/main/print/warning.h @@ -0,0 +1,111 @@ +/** + * FLL - Level 3 + * + * Project: Firewall + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Provides the print warning functionality. + * + * This is auto-included and should not need to be explicitly included. + */ +#ifndef _firewall_print_warning_h +#define _firewall_print_warning_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Print warning message regarding chain being meaningless at the given line. + * + * @param print + * The output structure to print to. + * + * This does not alter print.custom.setting.state.status. + * @param line + * The line number. + * + * @return + * F_okay on success. + * F_output_not on success, but no printing is performed. + * + * F_output_not (with error bit) if setting is NULL. + */ +#ifndef _di_firewall_print_warning_chain_meaningless_line_ + extern f_status_t firewall_print_warning_chain_meaningless_line(fl_print_t * const print, const f_number_unsigned_t line); +#endif // _di_firewall_print_warning_chain_meaningless_line_ + +/** + * Print warning message regarding a line having no Content or invalid Content for the given Object. + * + * @param print + * The output structure to print to. + * + * This does not alter print.custom.setting.state.status. + * @param line + * The line number. + * @param buffer + * The buffer containing the Object. + * @param range + * The range within the buffer representing the Object. + * + * @return + * F_okay on success. + * F_output_not on success, but no printing is performed. + * + * F_output_not (with error bit) if setting is NULL. + */ +#ifndef _di_firewall_print_warning_content_invalid_missing_line_ + extern f_status_t firewall_print_warning_content_invalid_missing_line(fl_print_t * const print, const f_number_unsigned_t line, const f_string_static_t buffer, const f_range_t range); +#endif // _di_firewall_print_warning_content_invalid_missing_line_ + +/** + * Print warning message regarding a line having no Object or the Object is invalid. + * + * @param print + * The output structure to print to. + * + * This does not alter print.custom.setting.state.status. + * @param line + * The line number. + * @param buffer + * The buffer containing the Object. + * @param range + * The range within the buffer representing the Object. + * + * @return + * F_okay on success. + * F_output_not on success, but no printing is performed. + * + * F_output_not (with error bit) if setting is NULL. + */ +#ifndef _di_firewall_print_warning_object_invalid_missing_line_ + extern f_status_t firewall_print_warning_object_invalid_missing_line(fl_print_t * const print, const f_number_unsigned_t line, const f_string_static_t buffer, const f_range_t range); +#endif // _di_firewall_print_warning_object_invalid_missing_line_ + +/** + * Print warning message regarding a show option not being known. + * + * @param print + * The output structure to print to. + * + * This does not alter print.custom.setting.state.status. + * @param option + * The show option that is not known. + * + * @return + * F_okay on success. + * F_output_not on success, but no printing is performed. + * + * F_output_not (with error bit) if setting is NULL. + */ +#ifndef _di_firewall_print_warning_show_option_unknown_ + extern f_status_t firewall_print_warning_show_option_unknown(fl_print_t * const print, const f_string_static_t option); +#endif // _di_firewall_print_warning_show_option_unknown_ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _firewall_print_warning_h diff --git a/sources/c/main/signal.c b/sources/c/main/signal.c new file mode 100644 index 0000000..3c16dab --- /dev/null +++ b/sources/c/main/signal.c @@ -0,0 +1,30 @@ +#include "firewall.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(_di_firewall_signal_handler_) && !defined(_di_thread_support_) + void firewall_signal_handler(firewall_main_t * const main) { + + if (!main) return; + + f_signal_set_empty(&main->program.signal.set); + f_signal_set_add(F_signal_abort, &main->program.signal.set); + f_signal_set_add(F_signal_broken_pipe, &main->program.signal.set); + f_signal_set_add(F_signal_hangup, &main->program.signal.set); + f_signal_set_add(F_signal_interrupt, &main->program.signal.set); + f_signal_set_add(F_signal_quit, &main->program.signal.set); + f_signal_set_add(F_signal_termination, &main->program.signal.set); + + fll_program_standard_signal_received_wait(&main->program, firewall_signal_check_failsafe_d); + + if (F_status_is_error(main->program.signal_status) && F_status_set_fine(main->program.signal_status) != F_interrupt) { + main->program.signal_received = F_signal_abort; + } + } +#endif // !defined(_di_firewall_signal_handler_) && !defined(_di_thread_support_) + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/main/signal.h b/sources/c/main/signal.h new file mode 100644 index 0000000..3812f66 --- /dev/null +++ b/sources/c/main/signal.h @@ -0,0 +1,55 @@ +/** + * FLL - Level 3 + * + * Project: Firewall + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Provides signal functionality. + * + * This is auto-included and should not need to be explicitly included. + */ +#ifndef _firewall_signal_h +#define _firewall_signal_h + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Signal handler for signals/interrupts. + * + * This blocks until an expected signal is recieved. + * When an expected signal is received it then sets the + * + * If main.signal is non-zero, then this handles the following signals: + * - F_signal_abort + * - F_signal_broken_pipe + * - F_signal_hangup + * - F_signal_interrupt + * - F_signal_quit + * - F_signal_termination + * + * @param main + * The main program and settings data. + * + * Must not be NULL. + * + * This alters main.program.signal_received, setting it to a received signal. + * This alters main.program.signal_status. + * + * This does not alter main.setting.state.status. + * + * @see f_signal_set_add() + * @see f_signal_set_empty() + * @see fll_program_standard_signal_received_wait() + */ +#if !defined(_di_firewall_signal_handler_) && !defined(_di_thread_support_) + extern void firewall_signal_handler(firewall_main_t * const main); +#endif // !defined(_di_firewall_signal_handler_) && !defined(_di_thread_support_) + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _firewall_signal_h diff --git a/sources/c/main/thread.c b/sources/c/main/thread.c new file mode 100644 index 0000000..b8803f5 --- /dev/null +++ b/sources/c/main/thread.c @@ -0,0 +1,22 @@ +#include "firewall.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(_di_firewall_thread_signal_) && !defined(_di_thread_support_) + void * firewall_thread_signal(void * const main) { + + f_thread_cancel_state_set(PTHREAD_CANCEL_DEFERRED, 0); + + if (main) { + firewall_signal_handler((firewall_main_t *) main); + } + + return 0; + } +#endif // !defined(_di_firewall_thread_signal_) && !defined(_di_thread_support_) + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/sources/c/main/thread.h b/sources/c/main/thread.h new file mode 100644 index 0000000..12f6483 --- /dev/null +++ b/sources/c/main/thread.h @@ -0,0 +1,46 @@ +/** + * FLL - Level 3 + * + * Project: Firewall + * API Version: 0.7 + * Licenses: lgpl-2.1-or-later + * + * Provides thread functionality. + * + * This is auto-included and should not need to be explicitly included. + */ +#ifndef _firewall_thread_h +#define _firewall_thread_h + +/** + * Thread handler for signals/interrupts. + * + * If main.signal is non-zero, then this handles the following signals: + * - F_signal_abort + * - F_signal_broken_pipe + * - F_signal_hangup + * - F_signal_interrupt + * - F_signal_quit + * - F_signal_termination + * + * @param main + * The program and settings data. + * + * Must be of type firewall_main_t. + * + * @return + * 0, always. + * + * @see f_thread_cancel_state_set() + * + * @see firewall_signal_handler() + */ +#if !defined(_di_firewall_thread_signal_) && !defined(_di_thread_support_) + extern void * firewall_thread_signal(void * const main); +#endif // !defined(_di_firewall_thread_signal_) && !defined(_di_thread_support_) + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _firewall_thread_h