#!/usr/bin/bash

# source bash base library
# shellcheck disable=SC1091
source /usr/libexec/bash-base.bash || {
        echo "$0: fatal error: failed to source /usr/libexec/bash-base.bash" >&2
        exit 1
}

bb_require_libs ldapusermgmt/common

# find_user_data <retvn> <user-cn> <user-homedir> [<extra-path> ..]
# all '%u' in extra-path will be replaced by user-cn
function find_user_data() {
    local _retvn="$1"
    local _user_cn="$2"
    local _user_homedir="$3"
    shift 3

    local -n _ret_ref="$_retvn"
    _ret_ref=()

    if [ -d "$_user_homedir" ]
    then
        # shellcheck disable=SC2178
        _ret_ref="$_user_homedir"
    else
        bb_msg warning "homedir of user $_user_cn not found: $_user_homedir"
    fi

    # check extra paths
    local _path
    for _path in "$@"
    do
        _path="${_path//%u/$_user_cn}"
        if [ -e "$_path" ]
        then
            _ret_ref+=("$_path")
        fi
    done
}

# backup_paths <name> <path-file> [<compress-program>]
function backup_paths() {
    (( $# == 2 || $# == 3 )) || \
        bb_fatal "backup_paths called with $# instead of 2 or 3 args"

    local _name="$1"
    local _path_file="$2"
    local _compress_program="${3-pixz}"

    [ -f "$_path_file" ] || \
        bb_fatal "backup_paths: path-file does not exist: $_path_file"

    [ -n "${HOMEDIR_BACKUP_PATH-}" ] || {
        bb_msg err "no homedir host backup path set"
        return 1
    }

    [ -d "$HOMEDIR_BACKUP_PATH" ] || {
        bb_msg err "homedir backup path is not dir: $HOMEDIR_BACKUP_PATH"
        return 1
    }

    local _backup_target
    printf -v _backup_target "%s/%s" \
        "$HOMEDIR_BACKUP_PATH" "${_name}_$(date '+%F_%T').tar.xz"

    if [ -f "$_backup_target" ]
    then
        bb_msg err "backup target already exists: $_backup_target"
        return 1
    fi

    local _tar_ops=("--sparse" \
        "--absolute-names" \
        "--use-compress-program=${_compress_program}" \
    "--ignore-failed-read"
        "--exclude-caches")

    [ -z "${BACKUP_EXCLUDE_PATHS[*]-}" ] || {
        printf "%s\n" "${BACKUP_EXCLUDE_PATHS[@]}" > "$TMPDIR/exclude-paths"
        _tar_ops+=("--exclude-from=$TMPDIR/exclude-paths")
    }

    if [ -z "${DRYRUN-}" ]
    then
        tar "${_tar_ops[@]}" \
            -cf "$_backup_target" \
            --files-from="$_path_file" || {
            bb_msg err "backup tar failed with error: $?"
            return 1
        }
    else
        bb_msg info "[dry run] tar ${_tar_ops[*]}" \
            "-cf \"$_backup_target\"" \
            --files-from="$_path_file"
    fi
}

# backups and removes userdata for multiple users
# vars: DEL_MUL_NAME DEL_MUL_CNS DEL_MUL_HOMEDIRS DEL_MUL_EXTRA_PATHS
# where DEL_MUL_CNS and DEL_MUL_HOMEDIRS are arrays of same size and order
function op_delete_multiple_userdata() {
    local -a opdu__new_paths _opdu_paths=()

    local -i i
    for ((i=0; i < ${#DEL_MUL_CNS[@]}; i++))
    do
        if (( ${#DEL_MUL_EXTRA_PATHS[@]} > 0 ))
        then
            find_user_data opdu__new_paths "${DEL_MUL_CNS[$i]}" \
                "${DEL_MUL_HOMEDIRS[$i]}" "${DEL_MUL_EXTRA_PATHS[@]}"
        else
            find_user_data opdu__new_paths "${DEL_MUL_CNS[$i]}" \
                "${DEL_MUL_HOMEDIRS[$i]}"
        fi
        [ -z "${opdu__new_paths[*]-}" ] || \
            _opdu_paths+=("${opdu__new_paths[@]}")
    done

    [ -n "${_opdu_paths[*]-}" ] || {
        bb_msg info "nothing found to backup and delete"
        return 0
    }

    printf "%s\n" "${_opdu_paths[@]}" > "$TMPDIR/backup-paths"

    backup_paths "${DEL_MUL_NAME}" "$TMPDIR/backup-paths" || {
        [ -n "${FORCE-}" ] || {
            bb_msg warning "backup failed and -F (force) is not set," \
                "aborting to delete multiple users: $DEL_MUL_NAME"
            return 1
        }
    }

    bb_msg debug "now deleting userdata for ${#DEL_MUL_CNS[@]} users:" \
        "${DEL_MUL_CNS[*]}"
    if [ -z "${DRYRUN-}" ]
    then
        rm -rf "${_opdu_paths[@]}" || \
            bb_msg err "delete-userdata: failed to: rm -rf ${_opdu_paths[*]}"
    else
        bb_msg info "[dry run] deleting userdata for $DEL_MUL_NAME:" \
            "rm -rf ${_opdu_paths[*]}"
    fi
}

# vars: CU_UID CU_GID CU_HOMEPATH CU_HOMEQUOTA CU_SKEL
function op_create_userdata() {
    local _var
    for _var in CU_UID CU_GID CU_HOMEPATH
    do
        [ -v "$_var" ] || {
            bb_msg err "create_userdata misses mandatory variable: $_var"
            return 1
        }
    done

    [ -d "$CU_HOMEPATH" ] && {
        bb_msg err "aborting, homedir already exists: $CU_HOMEPATH"
        return 1
    }

    [ -z "$CU_SKEL" ] && CU_SKEL=/etc/skel
    [ -d "$CU_SKEL" ] || {
        bb_msg err "aborting, skel dir not found: $CU_SKEL"
        return 1
    }

    bb_msg debug "now creating userdata: uid=$CU_UID gid=$CU_GID" \
       "homedir=$CU_HOMEPATH skel=${CU_SKEL-} homequota=${CU_HOMEQUOTA-}"

    if [ -z "${DRYRUN-}" ]
    then
        cp -r "$CU_SKEL" "$CU_HOMEPATH" || {
            bb_msg err "aborting, failed to create homedir: $CU_HOMEPATH"
            rm -rf "$CU_HOMEPATH" || \
                bb_msg warning "failed to cleanup failed cp"
            return 1
        }
        chown -R "$CU_UID":"$CU_GID" "$CU_HOMEPATH" || {
            bb_msg err "aborting, failed to chown homedir: $CU_HOMEPATH"
            rm -rf "$CU_HOMEPATH" || \
                bb_msg warning "failed to cleanup failed chown"
            return 1
        }
        chmod 750 "$CU_HOMEPATH" || {
            bb_msg err "aborting, failed to chmod homedir: $CU_HOMEPATH"
            rm -rf "$CU_HOMEPATH" || \
                bb_msg warning "failed to cleanup failed chmod"
            return 1
        }

        [ -z "${CU_HOMEQUOTA-}" ] || {
            setquota -u "$CU_UID" "$CU_HOMEQUOTA" "$CU_HOMEQUOTA" 0 0 \
                "${CU_HOMEPATH%/*}" || \
                bb_msg err "failed to set homedir quota, not aborting"
        }
    else
        bb_msg info "[dry run] creating homedir $CU_HOMEPATH" \
            "of skel $CU_SKEL with uid:gid=$CU_UID:$CU_GID"
        [ -z "${CU_HOMEQUOTA-}" ] || \
            bb_msg info "[dry run] setting homedir quota to $CU_HOMEQUOTA"
    fi
}

function op_move_homedir() {
    bb_msg info "operation move_homedir not yet implemented!"
}

function cleanup() {
    [ -z "${TMPDIR-}" ] || rm -rf "$TMPDIR"
}

function main() {
    verbosity_init stdout

    (( $# == 0 )) || bb_fatal "arguments specified but must not"
    if [ -t 0 ]
    then
        bb_fatal "this helper program must not be called itself"
    fi

    local -i _linenr=0
    local _line
    while true
    do
        _linenr="$(( _linenr + 1 ))"
        if read -r _line
        then
            case "$_line" in
                "start "*)
                    declare -g OPERATION
                    OPERATION="${_line#start }"
                    break
                    ;; # done reading variables
                "declare "*) eval "$_line";;
                *) bb_fatal "illegal variable line $_linenr: $_line"
            esac
        else
            bb_fatal "EOF while in read_vars"
        fi
    done

    [ -z "${VERBOSITY-}" ] || \
        verbosity_set "$VERBOSITY"

    declare -g TMPDIR
    TMPDIR=$(mktemp -d /tmp/lumfileshelper.XXXXXXXXXXX) || \
        bb_fatal "failed to: mktemp -d /tmp/lumfileshelper.XXXXXXXXXXX"
    bb_register_exit_hook cleanup
    chmod 700 "$TMPDIR"
    bb_msg debug "using temp dir: $TMPDIR"

    case "${OPERATION-}" in
        nop) bb_msg debug "nop operation completed successfully";;
        create_userdata|delete_multiple_userdata|move_homedir)
            "op_$OPERATION" || bb_quit "$?";;
        *) bb_quit 1 "unknown or no operation: ${OPERATION-}"
    esac
    bb_msg debug "successfully quitting"
}

main "$@"
bb_quit 0
