diff --git a/containers/bookstack/scripts/bookstack_install_hooks.sh b/containers/bookstack/scripts/bookstack_install_hooks.sh index 2e319e7..a178146 100644 --- a/containers/bookstack/scripts/bookstack_install_hooks.sh +++ b/containers/bookstack/scripts/bookstack_install_hooks.sh @@ -46,17 +46,23 @@ bookstack_install_post_start() fi isSuccessful "Bookstack is online (HTTP ${bookstack_http_code})." + # Target the container by $app_name, never the literal "bookstack": under + # multi-instance this hook is cloned for each instance, and a hardcoded name + # pointed every instance's admin bootstrap at the BASE app's container — + # provisioning (and, in the branch below, DELETING) users in the wrong + # database. instanceCreate's rewriter can't catch it either, since the + # container name here doesn't directly follow `docker exec`. local bookstack_create_output bookstack_create_output=$(runFileOp docker exec \ -e EZ_BS_NEW_EMAIL="$bookstack_target_email" \ -e EZ_BS_NEW_PASS="$bookstack_target_pass" \ - bookstack sh -c 'cd /app/www && s6-setuidgid abc php artisan bookstack:create-admin --no-ansi --email="$EZ_BS_NEW_EMAIL" --name=Admin --password="$EZ_BS_NEW_PASS" 2>&1') + "$app_name" sh -c 'cd /app/www && s6-setuidgid abc php artisan bookstack:create-admin --no-ansi --email="$EZ_BS_NEW_EMAIL" --name=Admin --password="$EZ_BS_NEW_PASS" 2>&1') local bookstack_create_rc=$? if [[ $bookstack_create_rc -eq 0 ]]; then isSuccessful "Bookstack admin account created (email: $bookstack_target_email)." if [[ "$bookstack_target_email" != "admin@admin.com" ]]; then - runFileOp docker exec -i bookstack php /app/www/artisan tinker --no-ansi >/dev/null 2>&1 <<'PHP' + runFileOp docker exec -i "$app_name" php /app/www/artisan tinker --no-ansi >/dev/null 2>&1 <<'PHP' $c = class_exists('\BookStack\Users\Models\User') ? '\BookStack\Users\Models\User' : '\BookStack\Auth\User'; optional($c::where('email', 'admin@admin.com')->first())->delete(); PHP diff --git a/scripts/database/tables/db_create_tables.sh b/scripts/database/tables/db_create_tables.sh index d1c6192..acc65e0 100755 --- a/scripts/database/tables/db_create_tables.sh +++ b/scripts/database/tables/db_create_tables.sh @@ -104,8 +104,7 @@ databaseCreateTables() status TEXT DEFAULT 'active', created_date DATE DEFAULT CURRENT_DATE, created_time TIME DEFAULT CURRENT_TIME, - UNIQUE(app_name, resource_type, service_name), - UNIQUE(resource_type, resource_value) + UNIQUE(app_name, resource_type, service_name) );") checkSuccess "Creating unified network_resources table" @@ -121,7 +120,81 @@ databaseCreateTables() local result; result=$(sqlite3 "$docker_dir/$db_file" "CREATE INDEX IF NOT EXISTS idx_network_resources_parent_service ON network_resources(parent_service);") checkSuccess "Creating network resources parent service index" fi + + # Runs for fresh AND existing databases (this function is re-run on every + # startup), so an install created before the constraint was scoped is + # repaired in place. + databaseMigrateNetworkResourcesUnique else echo "SQLite3 is not installed. Skipping table creation." fi } + +# Scope the global-uniqueness constraint on network_resources to the resources +# that are actually globally unique. +# +# The table shipped with UNIQUE(resource_type, resource_value). That is right for +# 'ip' and 'port' — no two apps may hold the same host port or container IP — but +# the port-tag writer stores descriptive rows in the same table and writes them +# with INSERT OR REPLACE, so each install DELETED the matching row from whichever +# app held it: +# port_tag_internal the CONTAINER-side port: every web app uses 80 +# traefik_managed 'true'/'false' — two possible values, so the whole table +# url_accessible could only ever hold ONE row of each, for one app +# Consequences: the firewall rebuild's traefik_managed LEFT JOIN reads NULL for +# every app but the last one installed, and in rooted mode a stolen +# port_tag_internal makes ufw-docker fall back to the EXTERNAL port — the exact +# "cannot find the published port" failure firewall_rebuild_from_db.sh warns +# about. Rows already lost are not reconstructable here; each app repopulates its +# own on the next `libreportal app install `. +# +# SQLite cannot drop a table constraint, so this rebuilds the table when the +# legacy constraint is still present, then enforces the narrow rule as a partial +# unique index. Idempotent: once migrated, the guard skips it. +databaseMigrateNetworkResourcesUnique() +{ + local table_sql + table_sql=$(sqlite3 "$docker_dir/$db_file" "SELECT sql FROM sqlite_master WHERE type='table' AND name='network_resources';" 2>/dev/null) + [[ -n "$table_sql" ]] || return 0 + + if [[ "$table_sql" == *"UNIQUE(resource_type, resource_value)"* ]]; then + # Single transaction: either the whole swap lands or the old table stays. + local result; result=$(sqlite3 "$docker_dir/$db_file" " + PRAGMA foreign_keys=off; + BEGIN TRANSACTION; + CREATE TABLE network_resources_migrated ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + app_name TEXT NOT NULL, + resource_type TEXT NOT NULL, + resource_value TEXT NOT NULL, + service_name TEXT DEFAULT 'main', + parent_service TEXT DEFAULT NULL, + status TEXT DEFAULT 'active', + created_date DATE DEFAULT CURRENT_DATE, + created_time TIME DEFAULT CURRENT_TIME, + UNIQUE(app_name, resource_type, service_name) + ); + INSERT INTO network_resources_migrated + SELECT id, app_name, resource_type, resource_value, service_name, + parent_service, status, created_date, created_time + FROM network_resources; + DROP TABLE network_resources; + ALTER TABLE network_resources_migrated RENAME TO network_resources; + CREATE INDEX IF NOT EXISTS idx_network_resources_app ON network_resources(app_name); + CREATE INDEX IF NOT EXISTS idx_network_resources_type ON network_resources(resource_type); + CREATE INDEX IF NOT EXISTS idx_network_resources_value ON network_resources(resource_value); + CREATE INDEX IF NOT EXISTS idx_network_resources_status ON network_resources(status); + CREATE INDEX IF NOT EXISTS idx_network_resources_parent_service ON network_resources(parent_service); + COMMIT; + " 2>&1) + if [[ -n "$result" ]]; then + isNotice "network_resources migration reported: $result" + fi + checkSuccess "Scoping network_resources uniqueness to ip/port" + fi + + # The narrow rule, as a partial index — still blocks two apps claiming the + # same host port or IP, and lets the descriptive rows coexist. Silent: it is + # a no-op on every startup after the first. + local result; result=$(sqlite3 "$docker_dir/$db_file" "CREATE UNIQUE INDEX IF NOT EXISTS idx_network_resources_global_value ON network_resources(resource_type, resource_value) WHERE resource_type IN ('ip','port');" 2>/dev/null) +} diff --git a/scripts/instance/instance_create.sh b/scripts/instance/instance_create.sh index dbbe5c8..5f09546 100644 --- a/scripts/instance/instance_create.sh +++ b/scripts/instance/instance_create.sh @@ -94,6 +94,19 @@ _instanceRewriteCompose() { sed -i -E "s/(container_name:[[:space:]]*)${type}\b/\1${slug}/g" "$f" # 3. The files-backup label's container ref (libreportal.backup.files: ":/..."). sed -i -E "s/(libreportal\.backup\.files:[[:space:]]*\")${type}\b/\1${slug}/g" "$f" + # 4. The per-app tag namespace. tagsProcessorAppConfigValues derives tag names + # mechanically from the config keys (CFG__APP_KEY_1 -> the tag + # _APP_KEY_1_TAG), so a clone still carrying the TYPE's tag names has + # nothing to match its own CFG__* vars: the placeholders survive and + # the pre-start guard refuses to launch the instance. + # Deliberately narrow — the tag name right after the #LIBREPORTAL| marker, + # and the *_DATA placeholder tokens. A blanket _ rewrite would also + # hit an app whose compose sets a real container env var named after itself + # (- _SECRET=...), renaming the variable the image reads. + local type_u="${type^^}" slug_u="${slug^^}" + type_u="${type_u//-/_}"; slug_u="${slug_u//-/_}" + sed -i -E "s/(#LIBREPORTAL\|)${type_u}_/\1${slug_u}_/g" "$f" + sed -i -E "s/\b${type_u}_([A-Z0-9_]*)_DATA\b/${slug_u}_\1_DATA/g" "$f" } # Clone + prefix-rename the per-app tools/scripts so an instance's helpers target @@ -117,6 +130,17 @@ _instanceRewriteTools() { sed -i -E "s/\b${type}_/${slug}_/g" "$f" sed -i -E "s/(docker[[:space:]]+(exec|logs|restart|stop|start|inspect)[[:space:]]+)${type}\b/\1${slug}/g" "$f" sed -i -E "s/\b${type}\.config\b/${slug}.config/g" "$f" + # Config reads are uppercase and so escape the lowercase rename above: + # an instance hook left reading CFG__ADMIN_EMAIL would provision + # itself from the type's config (its own value silently ignored). + sed -i -E "s/\bCFG_${type^^}_/CFG_${slug^^}_/g" "$f" + # container="" / container_name="" holds the docker target + # for exec-based helpers (auth adapters, tools). The bare literal has + # no trailing underscore, so the rename above misses it and the clone + # would operate on the BASE app's container. Kept to these two + # assignment forms — a blanket bare- rewrite would hit image + # names and prose. + sed -i -E "s/(\b(container|container_name)=\")${type}(\")/\1${slug}\3/g" "$f" done done } @@ -202,7 +226,27 @@ instanceCreate() { isSuccessful "Instance template ready: $slug (instance of $type)" - # 5. Hand off to the standard installer — from here it's just another app. + # 5. Make the instance's freshly-cloned installers/hooks callable in THIS + # process. Both loaders ran at startup, before this dir existed: the eager + # scan (sourceScanFiles "containers") never saw it, and the lazy manifest + # has no stub for it. Without this, _appCallHook's `declare -F` finds + # nothing and every _install_* hook silently no-ops — for bookstack + # that is the readiness probe and the admin-account bootstrap, so the + # instance installs "successfully" with no usable login. + local _inst_f + while IFS= read -r -d '' _inst_f; do + source "$_inst_f" + done < <(find "$inst_dir" -maxdepth 2 -type d -name resources -prune -o -type f -name '*.sh' -print0 2>/dev/null) + + # Persist that for later runs (and the WebUI): regenerate the file arrays + + # function manifest now that a new app dir exists. Best-effort — a stale + # manifest only affects lazy mode, and the in-process sourcing above already + # covers this install. + if declare -F lpRegenArrays >/dev/null 2>&1; then + lpRegenArrays force >/dev/null 2>&1 || true + fi + + # 6. Hand off to the standard installer — from here it's just another app. if ! declare -F dockerInstallApp >/dev/null 2>&1; then isError "dockerInstallApp unavailable; instance template created but not installed." return 1 diff --git a/scripts/network/ports/allocation/port_update_compose_tags.sh b/scripts/network/ports/allocation/port_update_compose_tags.sh index 0a0d7e7..c431e62 100755 --- a/scripts/network/ports/allocation/port_update_compose_tags.sh +++ b/scripts/network/ports/allocation/port_update_compose_tags.sh @@ -5,7 +5,18 @@ portUpdateComposeTags() { local app_name="$1" local full_file_path="$2" - + + # This function is the only INSERT OR REPLACE writer into network_resources, + # so it is where the legacy UNIQUE(resource_type, resource_value) did its + # damage — each run silently stole other apps' port_tag_internal / + # traefik_managed / url_accessible rows. Repair the constraint here rather + # than only in databaseCreateTables: that runs from startPreInstall, which a + # working install never re-runs, so existing installs would keep corrupting + # themselves until a full reinstall. One guarded SELECT; a no-op once done. + if declare -F databaseMigrateNetworkResourcesUnique >/dev/null 2>&1; then + databaseMigrateNetworkResourcesUnique + fi + local port_tags_found=() local port_numbers=() diff --git a/scripts/source/files/arrays/function_manifest.sh b/scripts/source/files/arrays/function_manifest.sh index 76dc347..b43520a 100644 --- a/scripts/source/files/arrays/function_manifest.sh +++ b/scripts/source/files/arrays/function_manifest.sh @@ -58,12 +58,12 @@ declare -gA LP_FN_MAP=( [appLinkdingResetPassword]="linkding/tools/linkding_reset_password.sh" [appLinkdingSetAdmin]="linkding/tools/linkding_set_admin.sh" [appMatrixCreateAccount]="matrix/tools/matrix_create_account.sh" - [appMatrixDeactivateUser]="matrix/tools/matrix_deactivate_user.sh" + [appMatrixDeleteUser]="matrix/tools/matrix_delete_user.sh" [appMatrixListUsers]="matrix/tools/matrix_list_users.sh" [appMatrixResetPassword]="matrix/tools/matrix_reset_password.sh" [appMatrixSetAdmin]="matrix/tools/matrix_set_admin.sh" [appMattermostCreateAccount]="mattermost/tools/mattermost_create_account.sh" - [appMattermostDeactivateUser]="mattermost/tools/mattermost_deactivate_user.sh" + [appMattermostDeleteUser]="mattermost/tools/mattermost_delete_user.sh" [appMattermostListUsers]="mattermost/tools/mattermost_list_users.sh" [appMattermostResetPassword]="mattermost/tools/mattermost_reset_password.sh" [appMattermostSetAdmin]="mattermost/tools/mattermost_set_admin.sh" @@ -86,7 +86,7 @@ declare -gA LP_FN_MAP=( [_appReqServiceInstalled]="checks/requirements/check_app_install.sh" [_appReqServiceMsg]="checks/requirements/check_app_install.sh" [appRocketchatCreateAccount]="rocketchat/tools/rocketchat_create_account.sh" - [appRocketchatDeactivateUser]="rocketchat/tools/rocketchat_deactivate_user.sh" + [appRocketchatDeleteUser]="rocketchat/tools/rocketchat_delete_user.sh" [appRocketchatEnableUser]="rocketchat/tools/rocketchat_enable_user.sh" [appRocketchatListUsers]="rocketchat/tools/rocketchat_list_users.sh" [appRocketchatResetPassword]="rocketchat/tools/rocketchat_reset_password.sh" @@ -103,7 +103,7 @@ declare -gA LP_FN_MAP=( [appStalwartSetMode]="stalwart/tools/stalwart_set_mode.sh" [appStalwartShowDns]="stalwart/tools/stalwart_show_dns.sh" [appStatus]="app/app_status.sh" - [appStoatDisableUser]="stoat/tools/stoat_disable_user.sh" + [appStoatDeleteUser]="stoat/tools/stoat_delete_user.sh" [appStoatEnableUser]="stoat/tools/stoat_enable_user.sh" [appStoatListUsers]="stoat/tools/stoat_list_users.sh" [appTraefikExtraMiddlewares_onlyoffice]="onlyoffice/scripts/onlyoffice_traefik.sh" @@ -405,6 +405,7 @@ declare -gA LP_FN_MAP=( [databaseListAllApps]="database/app/db_list_all_apps.sh" [databaseListInstalledApp]="database/app/db_list_installed_app.sh" [databaseListInstalledApps]="database/app/db_list_installed_apps.sh" + [databaseMigrateNetworkResourcesUnique]="database/tables/db_create_tables.sh" [databaseOptionInsert]="database/insert/db_insert_option.sh" [databasePortOpenInsert]="database/insert/db_insert_port_open.sh" [databasePortUsedInsert]="database/insert/db_insert_port_used.sh" @@ -1181,12 +1182,12 @@ declare -gA LP_FN_ROOT=( [appLinkdingResetPassword]="containers" [appLinkdingSetAdmin]="containers" [appMatrixCreateAccount]="containers" - [appMatrixDeactivateUser]="containers" + [appMatrixDeleteUser]="containers" [appMatrixListUsers]="containers" [appMatrixResetPassword]="containers" [appMatrixSetAdmin]="containers" [appMattermostCreateAccount]="containers" - [appMattermostDeactivateUser]="containers" + [appMattermostDeleteUser]="containers" [appMattermostListUsers]="containers" [appMattermostResetPassword]="containers" [appMattermostSetAdmin]="containers" @@ -1209,7 +1210,7 @@ declare -gA LP_FN_ROOT=( [_appReqServiceInstalled]="scripts" [_appReqServiceMsg]="scripts" [appRocketchatCreateAccount]="containers" - [appRocketchatDeactivateUser]="containers" + [appRocketchatDeleteUser]="containers" [appRocketchatEnableUser]="containers" [appRocketchatListUsers]="containers" [appRocketchatResetPassword]="containers" @@ -1226,7 +1227,7 @@ declare -gA LP_FN_ROOT=( [appStalwartSetMode]="containers" [appStalwartShowDns]="containers" [appStatus]="scripts" - [appStoatDisableUser]="containers" + [appStoatDeleteUser]="containers" [appStoatEnableUser]="containers" [appStoatListUsers]="containers" [appTraefikExtraMiddlewares_onlyoffice]="containers" @@ -1528,6 +1529,7 @@ declare -gA LP_FN_ROOT=( [databaseListAllApps]="scripts" [databaseListInstalledApp]="scripts" [databaseListInstalledApps]="scripts" + [databaseMigrateNetworkResourcesUnique]="scripts" [databaseOptionInsert]="scripts" [databasePortOpenInsert]="scripts" [databasePortUsedInsert]="scripts" @@ -2339,12 +2341,12 @@ appLinkdingListUsers() { unset -f appLinkdingListUsers; __lpAutoload "${install_ appLinkdingResetPassword() { unset -f appLinkdingResetPassword; __lpAutoload "${install_containers_dir}linkding/tools/linkding_reset_password.sh"; appLinkdingResetPassword "$@"; } appLinkdingSetAdmin() { unset -f appLinkdingSetAdmin; __lpAutoload "${install_containers_dir}linkding/tools/linkding_set_admin.sh"; appLinkdingSetAdmin "$@"; } appMatrixCreateAccount() { unset -f appMatrixCreateAccount; __lpAutoload "${install_containers_dir}matrix/tools/matrix_create_account.sh"; appMatrixCreateAccount "$@"; } -appMatrixDeactivateUser() { unset -f appMatrixDeactivateUser; __lpAutoload "${install_containers_dir}matrix/tools/matrix_deactivate_user.sh"; appMatrixDeactivateUser "$@"; } +appMatrixDeleteUser() { unset -f appMatrixDeleteUser; __lpAutoload "${install_containers_dir}matrix/tools/matrix_delete_user.sh"; appMatrixDeleteUser "$@"; } appMatrixListUsers() { unset -f appMatrixListUsers; __lpAutoload "${install_containers_dir}matrix/tools/matrix_list_users.sh"; appMatrixListUsers "$@"; } appMatrixResetPassword() { unset -f appMatrixResetPassword; __lpAutoload "${install_containers_dir}matrix/tools/matrix_reset_password.sh"; appMatrixResetPassword "$@"; } appMatrixSetAdmin() { unset -f appMatrixSetAdmin; __lpAutoload "${install_containers_dir}matrix/tools/matrix_set_admin.sh"; appMatrixSetAdmin "$@"; } appMattermostCreateAccount() { unset -f appMattermostCreateAccount; __lpAutoload "${install_containers_dir}mattermost/tools/mattermost_create_account.sh"; appMattermostCreateAccount "$@"; } -appMattermostDeactivateUser() { unset -f appMattermostDeactivateUser; __lpAutoload "${install_containers_dir}mattermost/tools/mattermost_deactivate_user.sh"; appMattermostDeactivateUser "$@"; } +appMattermostDeleteUser() { unset -f appMattermostDeleteUser; __lpAutoload "${install_containers_dir}mattermost/tools/mattermost_delete_user.sh"; appMattermostDeleteUser "$@"; } appMattermostListUsers() { unset -f appMattermostListUsers; __lpAutoload "${install_containers_dir}mattermost/tools/mattermost_list_users.sh"; appMattermostListUsers "$@"; } appMattermostResetPassword() { unset -f appMattermostResetPassword; __lpAutoload "${install_containers_dir}mattermost/tools/mattermost_reset_password.sh"; appMattermostResetPassword "$@"; } appMattermostSetAdmin() { unset -f appMattermostSetAdmin; __lpAutoload "${install_containers_dir}mattermost/tools/mattermost_set_admin.sh"; appMattermostSetAdmin "$@"; } @@ -2367,7 +2369,7 @@ _appReqHasDomain() { unset -f _appReqHasDomain; __lpAutoload "${install_scripts_ _appReqServiceInstalled() { unset -f _appReqServiceInstalled; __lpAutoload "${install_scripts_dir}checks/requirements/check_app_install.sh"; _appReqServiceInstalled "$@"; } _appReqServiceMsg() { unset -f _appReqServiceMsg; __lpAutoload "${install_scripts_dir}checks/requirements/check_app_install.sh"; _appReqServiceMsg "$@"; } appRocketchatCreateAccount() { unset -f appRocketchatCreateAccount; __lpAutoload "${install_containers_dir}rocketchat/tools/rocketchat_create_account.sh"; appRocketchatCreateAccount "$@"; } -appRocketchatDeactivateUser() { unset -f appRocketchatDeactivateUser; __lpAutoload "${install_containers_dir}rocketchat/tools/rocketchat_deactivate_user.sh"; appRocketchatDeactivateUser "$@"; } +appRocketchatDeleteUser() { unset -f appRocketchatDeleteUser; __lpAutoload "${install_containers_dir}rocketchat/tools/rocketchat_delete_user.sh"; appRocketchatDeleteUser "$@"; } appRocketchatEnableUser() { unset -f appRocketchatEnableUser; __lpAutoload "${install_containers_dir}rocketchat/tools/rocketchat_enable_user.sh"; appRocketchatEnableUser "$@"; } appRocketchatListUsers() { unset -f appRocketchatListUsers; __lpAutoload "${install_containers_dir}rocketchat/tools/rocketchat_list_users.sh"; appRocketchatListUsers "$@"; } appRocketchatResetPassword() { unset -f appRocketchatResetPassword; __lpAutoload "${install_containers_dir}rocketchat/tools/rocketchat_reset_password.sh"; appRocketchatResetPassword "$@"; } @@ -2384,7 +2386,7 @@ appSetupComposeTags_wireguard() { unset -f appSetupComposeTags_wireguard; __lpAu appStalwartSetMode() { unset -f appStalwartSetMode; __lpAutoload "${install_containers_dir}stalwart/tools/stalwart_set_mode.sh"; appStalwartSetMode "$@"; } appStalwartShowDns() { unset -f appStalwartShowDns; __lpAutoload "${install_containers_dir}stalwart/tools/stalwart_show_dns.sh"; appStalwartShowDns "$@"; } appStatus() { unset -f appStatus; __lpAutoload "${install_scripts_dir}app/app_status.sh"; appStatus "$@"; } -appStoatDisableUser() { unset -f appStoatDisableUser; __lpAutoload "${install_containers_dir}stoat/tools/stoat_disable_user.sh"; appStoatDisableUser "$@"; } +appStoatDeleteUser() { unset -f appStoatDeleteUser; __lpAutoload "${install_containers_dir}stoat/tools/stoat_delete_user.sh"; appStoatDeleteUser "$@"; } appStoatEnableUser() { unset -f appStoatEnableUser; __lpAutoload "${install_containers_dir}stoat/tools/stoat_enable_user.sh"; appStoatEnableUser "$@"; } appStoatListUsers() { unset -f appStoatListUsers; __lpAutoload "${install_containers_dir}stoat/tools/stoat_list_users.sh"; appStoatListUsers "$@"; } appTraefikExtraMiddlewares_onlyoffice() { unset -f appTraefikExtraMiddlewares_onlyoffice; __lpAutoload "${install_containers_dir}onlyoffice/scripts/onlyoffice_traefik.sh"; appTraefikExtraMiddlewares_onlyoffice "$@"; } @@ -2686,6 +2688,7 @@ databaseInstallApp() { unset -f databaseInstallApp; __lpAutoload "${install_scri databaseListAllApps() { unset -f databaseListAllApps; __lpAutoload "${install_scripts_dir}database/app/db_list_all_apps.sh"; databaseListAllApps "$@"; } databaseListInstalledApp() { unset -f databaseListInstalledApp; __lpAutoload "${install_scripts_dir}database/app/db_list_installed_app.sh"; databaseListInstalledApp "$@"; } databaseListInstalledApps() { unset -f databaseListInstalledApps; __lpAutoload "${install_scripts_dir}database/app/db_list_installed_apps.sh"; databaseListInstalledApps "$@"; } +databaseMigrateNetworkResourcesUnique() { unset -f databaseMigrateNetworkResourcesUnique; __lpAutoload "${install_scripts_dir}database/tables/db_create_tables.sh"; databaseMigrateNetworkResourcesUnique "$@"; } databaseOptionInsert() { unset -f databaseOptionInsert; __lpAutoload "${install_scripts_dir}database/insert/db_insert_option.sh"; databaseOptionInsert "$@"; } databasePortOpenInsert() { unset -f databasePortOpenInsert; __lpAutoload "${install_scripts_dir}database/insert/db_insert_port_open.sh"; databasePortOpenInsert "$@"; } databasePortUsedInsert() { unset -f databasePortUsedInsert; __lpAutoload "${install_scripts_dir}database/insert/db_insert_port_used.sh"; databasePortUsedInsert "$@"; }