#!/bin/bash

separator=':'
declare -a pid_list=()  # Массив для хранения PID фоновых процессов

show_help() {
    echo "$(basename "$0") - утилита для объединения файлов из слоёв overlayfs"
    echo "
Использование:
    $(basename "$0") [опции] ФАЙЛ1 [ФАЙЛ2...]

Опции:
    -i|--inplace    Заменить файлы результатом (с созданием бэкапа)
    -s|--separator  Разделитель полей (по умолчанию ':')
    -h|--help       Эта справка

Примеры:
    # Показать объединённые версии файлов
    $(basename "$0") /etc/passwd /etc/group /etc/shadow

    # Заменить файлы
    $(basename "$0") -i /etc/passwd /etc/shadow
"
    exit 0
}

file_exists_in_layers() {
    local file="$1"
    [[ -f "$file" ]] && return 0
    [[ -d "/.memory/bundles" ]] && compgen -G "/.memory/bundles/*/$file" >/dev/null && return 0
    return 1
}

process_file() {
    local file="$1"
    local tmpfile
    tmpfile=$(mktemp)

    local layers=()
    [[ -f "$file" ]] && layers+=("$file")

    if [[ -d "/.memory/bundles" ]]; then
        while IFS= read -r -d '' layer; do
            layers+=("$layer")
        done < <(find "/.memory/bundles" -path "*$file" -type f -print0 2>/dev/null)
    fi

    declare -A seen
    for layer in "${layers[@]}"; do
        while IFS= read -r line; do
            local key="${line%%"$separator"*}"
            [[ -z "${seen[$key]}" ]] && {
                echo "$line"
                seen[$key]=1
            }
        done < "$layer"
    done > "$tmpfile"

    if (( inplace )); then
	perm=044
	own="0:0"
        if [[ -f "$file" ]] ; then
	    mv "$file" "${file}~"
	    perm=$(stat -c %a "${file}~")
	    own=$(stat -c %u:%g "${file}~")
	fi
	mv "$tmpfile" "$file"
	chown $own "$file"
	chmod $perm "$file"
        echo "Complete: $file" >&2
    else
        echo "=== $file ===" >&2
        cat "$tmpfile"
        rm -f "$tmpfile"
    fi
}

wait_for_jobs() {
    while (( ${#pid_list[@]} > 0 )); do
        local new_pid_list=()
        for pid in "${pid_list[@]}"; do
            [[ -d "/proc/$pid" ]] && new_pid_list+=("$pid")
        done
        pid_list=("${new_pid_list[@]}")
        (( ${#pid_list[@]} > 0 )) && sleep 0.1
    done
}

# Парсинг аргументов
while [[ $# -gt 0 ]]; do
    case "$1" in
        -h|--help) show_help ;;
        -i|--inplace) inplace=1 ;;
        -s|--separator)
            separator="$2"
            shift
            ;;
        *)
            if file_exists_in_layers "$1"; then
                files+=("$1")
            else
                echo "Error:  $1 not found in layers" >&2
                exit 1
            fi
            ;;
    esac
    shift
done

[[ ${#files[@]} -eq 0 ]] && { echo "Please specify files" >&2; exit 1; }

export separator inplace

# Запуск обработки всех файлов в фоне
for file in "${files[@]}"; do
    process_file "$file" &
    pid_list+=("$!")
done

# Ожидание завершения
wait_for_jobs
echo "Done" >&2

