diff --git a/scripts/source/loading/scan_files.sh b/scripts/source/loading/scan_files.sh index 77297ed..c008bed 100755 --- a/scripts/source/loading/scan_files.sh +++ b/scripts/source/loading/scan_files.sh @@ -15,12 +15,38 @@ sourceScanFiles() if [ -f "$file" ]; then local filename=$(basename "$file") local should_load=true - + # Skip .category files and excluded files if [[ "$file" =~ \.category$ ]] || [[ "$filename" == "app_categories" ]]; then should_load=false fi - + + # A file in a SUBDIRECTORY is only sourced when that directory is + # a declared config category (carries .category) — the same + # contract commandReloadConfigs enforces in the CLI wrapper. + # + # Sourcing means EXECUTING, so an unmarked directory used as + # ordinary storage turned its contents into a script. That is not + # hypothetical: storageIndexSet caches an app -> root TSV at + # configs/storage/app_locations, no .category alongside it. Every + # line there is ``, which bash reads as a command + # and its argument. Harmless while no slug matched a real + # executable — and a fork bomb the moment the row was for the app + # named `libreportal`, because that IS the CLI: sourcing ran + # `libreportal /libreportal-containers`, which re-entered this + # scan, which sourced the file again, one process pair per level + # until the host died of OOM. Every CLI invocation on the box, + # including the task processor's own, detonated it. + # + # Depth-1 files (directly in configs/) keep loading as before — + # only the category dirs gained a marker requirement. + if [ "$should_load" = true ]; then + local parent_dir="${file%/*}" + if [[ "$parent_dir" != "${folder_dir%/}" && ! -f "$parent_dir/.category" ]]; then + should_load=false + fi + fi + if [ "$should_load" = true ]; then source "$file" # echo "$load_type NEW FILE $file"