#!/bin/sh

po_domain="alterator-bacula"
alterator_api_version=1
restore_pid=
target_dir="${target_dir:-/mnt/destination}"
#path where backups was found
backup_path=

. alterator-sh-functions
. bacula-client-sh-functions
. bacula-local-sh-functions
. alterator-net-functions

do_notify()
{
    alterator-mailbox-send "$1 \"$(write_string "$2")\""
    sleep 1
}

do_notify_status()
{
    do_notify status "$1"
}

do_notify_stage()
{
    do_notify stage "$1"
}

do_notify_fatal_error()
{
    do_notify fatal-error "$1"
    bacula_daemon_off
}

do_notify_search_error()
{
    do_notify search-error
    bacula_daemon_off
}

do_notify_restore_error()
{
    do_notify restore-error
}

do_fstab()
{
    local target_path="$1";shift

    local installer_fstab_file=/tmp/fstab
    local target_fstab_file="$target_path/etc/fstab"

    [ -s "$installer_fstab_file" ] || return

    mkdir -p -- "$target_dir/etc"

    cp -f -- "$target_fstab_file" "$target_dir/etc/fstab.restored"
    [ -z "$(tail -c1 "$target_fstab_file")" ] || printf '\n' >>"$target_fstab_file"

    local fs_spec fs_file fs_vfstype fs_rest
    local qfs_spec qfs_file qfs_vfstype qfs_rest

    # move all partitions instead of swap from installer's fstab to system's one
    [ -z "$(tail -c1 "$target_fstab_file")" ] || printf '\n' >>"$target_fstab_file"

    while read fs_spec fs_file fs_vfstype fs_rest; do
	[ "$fs_vfstype" != "swap" ] || continue

	quote_sed_regexp_variable qfs_spec "$fs_spec"
	quote_sed_regexp_variable qfs_file "$fs_file"
	quote_sed_regexp_variable qfs_vfstype "$fs_vfstype"
	quote_sed_regexp_variable qfs_rest "$fs_rest"
	local re="^[[:space:]]*[^[:space:]]\+[[:space:]]\+$qfs_file[[:space:]]"
	if grep -qs "$re" "$target_fstab_file";then
	    sed \
		-e "s/${re}.*/$qfs_spec	$qfs_file	$qfs_vfstype	$qfs_rest/" \
		-i "$target_fstab_file"
	else
	    printf '%s\t%s\t%s\t%s\n' \
		"$fs_spec" \
		"$fs_file" \
		"$fs_vfstype" \
		"$fs_rest" >>"$target_fstab_file"
	fi
    done <"$installer_fstab_file"

    # update swap devices in target fstab
    local swap_re='^[[:space:]]*[^[:space:]]\+[[:space:]]\+[^[:space:]]\+[[:space:]]\+swap'
    sed "/$swap_re/d" -i "$target_fstab_file"
    grep "$swap_re" "$installer_fstab_file" >> "$target_fstab_file"
}

do_initrd()
{
    local target_path="$1";shift
    local image
    local version

    for image in $target_path/boot/initrd-*.img; do
	[ -f "$image" ] || continue
	version="${image%.img}"
	version="${version##$target_path/boot/initrd-}"
	echo "mkinitrd ${image##$target_path} $version" >&2
	cp -f -- "$image" "$image.restored"
	chroot "$target_path" mkinitrd -f "${image##$target_path}" "$version" ||:
    done
}

do_search()
{
    local target_path="$1";shift

    mkdir -p -- "$target_path"

    do_notify_stage "search"
    backup_path="$(bacula_device_find_path do_notify_status)"
    if  [ -z "$backup_path" ]; then
	do_notify_search_error
	return 1
    fi

    do_notify_stage "prepare"
    bacula_daemon_off
    bacula_local_storage_set_path "$backup_path"
    bacula_catalog_set_path "$target_path/$bacula_localstate_dir"


    do_notify_stage "restore-db"
    if ! bacula_catalog_restore "$backup_path" "$target_path";then
	do_notify_fatal_error "Unable to restore backup database"
	return 1
    fi

    if ! bacula_daemon_on;then
	do_notify_fatal_error "Unable to start daemon..."
	return 1
    fi

    do_notify_stage "done"
}

do_restore()
{
    local target_date="$1";shift
    local target_path="$1";shift

    do_notify_stage "prepare"

    # create minimum device set
    mkdir -p -- "$target_path/dev"
    cp -at "$target_path/dev" -- \
	/dev/null \
	/dev/zero \
	/dev/full \
	/dev/random \
	/dev/urandom \
	/dev/console \
	/dev/tty \
	/dev/ptmx

    # create temporary directory if it doesn't exist
    mkdir -p -- "$target_path/tmp"

    # bind virtual filesystems
    local path
    for path in /dev /dev/pts /proc /sys; do
	[ -d "$path" ] || continue
	mkdir -p -- "$target_path/$path"
	mount -o bind "$path" "$target_path/$path"
    done

    # start job to restore rest of the system
    local jobid="$(bacula_restore_all "$bacula_local_client_name" "$bacula_local_fileset_name" "$target_date" "$target_path")"

    if [ -z "$jobid" ];then
	do_notify_fatal_error "Unable to determine job id"
	return 1
    fi

    do_notify_stage "restore-system"

    while : ; do
	local status="$(bacula_job_status "$jobid")"
	case "$status" in
	    C)
		do_notify_status "`_ "Waiting..."`"
		;;
	    R|D|F|S|m|M|s|j|c|d|p|a|i)
		local filename="$(bacula_local_client_status)"
		do_notify_status "${filename#$target_dir}"
		;;
	    T|e)
	        break
	        ;;
	    B|E|f|A)
		do_notify_restore_error
		break #don't return, get a chance to finish restore process
		;;
	esac

	sleep 1
    done

    # restore fstab
    do_fstab "$target_path"

    # restore initrd
    do_initrd "$target_path"

    # stop server and release disk with backups
    bacula_daemon_off
    [ -z "$backup_path" ] || umount -l "$backup_path"

    if [ -f $target_dir/usr/sbin/alteratord ] && [ -f $target_dir/usr/lib/alterator/backend3/grub ]; then
	    alteratord_socket_dir="/var/run/alteratord"
	    # replace itself with alteratord from chroot
	    chroot "$target_dir" service alteratord start
	    mount -o bind "$target_dir/$alteratord_socket_dir" "$alteratord_socket_dir"

	    # wait until new alteratord is ready to use
	    alterator-wait
    fi

    # notify interface about finish
    do_notify_stage done
}

### initial actions
iface_up lo

on_message()
{
  case "$in_action" in
    search|restore)
	if [ -n "$restore_pid" ] && kill -0 "$restore_pid" 2>/dev/null;then
	    write_error "Process already running"
	    return
	fi
	case "$in_action" in
	    search)
		do_search "$target_dir"&
		;;
	    restore)
		if [ -z "$in_date" ];then
		    write_error "Please specify backup date"
		    return
		fi
		do_restore "$in_date" "$target_dir"&
		;;
	esac
	restore_pid=$!
	;;
    wait)
	if [ -n "$restore_pid" ] && kill -0 "$restore_pid" 2>/dev/null;then
	    wait "$restore_pid"
	fi
	;;
    list)
	case "$in__objects" in
	    date) bacula_local_backup_date_list|IFS='	' write_enum ;;
	esac
  esac
}

message_loop
