#!/bin/sh

. shell-config
. shell-var

po_domain="alterator-livecd"
alterator_api_version=1
source_dir="${source_dir:-/.ro}"
target_dir="${target_dir:-/mnt/destination}"
preinstall_hooks_dir=/usr/lib/alterator/hooks/livecd-preinstall.d
du_exclude_list='/mnt /home /media /run /var/run /srv'
install_pid=

slideshow_conf="/etc/alterator/slideshow.conf"
# Default slideshow timeout, sec
default_slideshow_step=30
default_slideshow_path="/usr/share/install2/slideshow"

export target_dir

. alterator-sh-functions
. livecd-functions
. install2-remount-functions

do_notify()
{
    alterator-mailbox-send "$1 \"$(write_string "$2")\""
    echo "message:$1 $2" >&2
    sleep 0.1
}

do_notify_error()
{
    do_notify error "$1"
}

do_notify_status()
{
    do_notify status "$1"
}

do_notify_stage()
{
    do_notify stage "$1"
}

##
# Return free space in bytes on mounted file system
#
free_space() {
        local target="$1" && shift

        [ -e "$target" ] || return 1

        df --block-size=1 "$target" | sed -e '1d' -e 's/[[:space:]]\+/ /g' | cut -d ' ' -f 4

        return 0
}

##
# copy squashfs image
#

do_install()
{
    local src="$1";shift
    local dst="$1";shift
    local total_size= total_files= free= checkpoint_step= checkpoint= pct= cur= dst_size=
    local checkpoints_number=200
    local count=0
    local prev_pct=-1
    local du_exclude_dir=
    local du_exclude_file=/tmp/alterator-livecd-du-exclude-list

    if [ ! -d "$src" ]; then
        do_notify_error "Can't find image mountpoint ($src)"
        return 1
    fi

    if ! mkdir -p -- "$dst";then
        do_notify_error "Can't write to $dst directory"
        return 1
    fi

    do_notify_stage preinstall

    shopt -sq dotglob

    total_size="$(du -sb "$src" 2>/dev/null | cut -f1)"
    total_files="$(find "$src"/* 2>/dev/null | wc -l)"
    if [ -z "$total_size" -o $total_files -eq 0 ] ; then
        do_notify_error "Can't calculate image size"
        return 1
    fi

    free=$(free_space "$dst")

    if [ $total_size -gt $free ]; then
        do_notify_error "No free space to copy image"
        return 1
    fi

    checkpoint_step="$(($total_files / $checkpoints_number))"

    do_notify_stage install

    checkpoint="$checkpoint_step"

    if [ -n "$(find "$dst" -mount -type f -print -quit)" ]; then
        do_notify_error "$dst is not empty!"
    fi

    # exclude specified directories from du counts
    # if needed (mounted to the $dst)
    touch "$du_exclude_file"
    for du_exclude_dir in $du_exclude_list; do
        if mount | egrep -qs "^/dev.+ ${dst%/}$du_exclude_dir.* type.+$"; then
            echo "${dst%/}$du_exclude_dir" >>"$du_exclude_file"
        fi
    done

    cp -avf "$src"/* "$dst" | while read cur; do
        count="$(($count + 1))"
        [ $count -ge $checkpoint ] || continue
        checkpoint="$(($checkpoint + $checkpoint_step))"
        dst_size="$(du -sb --exclude-from="$du_exclude_file" "$dst" 2>/dev/null | cut -f1)"
        pct="$(($dst_size * 100 / $total_size))"
        [ $pct -le 100 ] || pct=100
        # Don't sent the same percentage again
        [ $pct -gt $prev_pct ] || continue
        prev_pct="$pct"
        do_notify_status "$pct"
    done

    # Set right perms on root directory of installed system
    chmod 0755 "$dst"

    do_notify_stage postinstall

    for i in proc dev sys run; do
        mkdir -p -- "$dst/$i"
        mountpoint -q "$dst/$i" || mount --bind /$i "$dst/$i"
    done

    # Remount volumes (involves shutting down EVMS)
    if ! remount_chroot >&2; then
        do_notify_error "destination filesystem remount error, see /tmp/remount.log"
    fi

    # Mount cgroups in the $dst:
    # can be needed in case of systemd
    if mountpoint -q /sys/fs/cgroup; then
        mkdir -p -- "$dst"
        mountpoint -q "$dst/sys/fs/cgroup" || mount --rbind /sys/fs/cgroup "$dst/sys/fs/cgroup"
    fi

    # Run preinstall scripts
    run-parts "$preinstall_hooks_dir"

    alteratord_socket_dir="/var/run/alteratord"
    # replace itself with alteratord from chroot
    [ -n "${dst:-}" ] || return
    mount -o bind "$dst/$alteratord_socket_dir" "$alteratord_socket_dir"
    chroot "$dst" /etc/init.d/alteratord start

    # Mount root to target dir for access from chroot at finish stage
    mkdir -p "$dst/livecd-root"
    mount --rbind / "$dst/livecd-root" 2>/dev/null
    mount --make-rslave "$dst/livecd-root" 2>/dev/null

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

    # notify interface about finish
    do_notify_stage done
    sync

    return 0
}

### slideshow configuration
read_slideshow_conf()
{
    local step="$(shell_config_get "$slideshow_conf" step)"
    if [ -z "$step" ] || echo "$step" | egrep -vqs '^[[:digit:]]+$'; then
        step="$default_slideshow_step"
    fi
	write_string_param step "$step"

    local once="$(shell_config_get "$slideshow_conf" once)"
    if [ -n "$once" ] && shell_var_is_yes "$once"; then
        once='true'
    else
        once='false'
    fi
    write_bool_param once "$once"

    local url="$(shell_config_get "$slideshow_conf" url)"
    [ -n "$url" ] || url="$default_slideshow_path"
    write_string_param url "$url"
}

on_message()
{
        case "$in_action" in
                read)
                    case "$in__objects" in
                        slideshow-config)
                            read_slideshow_conf
                            ;;
                        *)
                        ;;
                    esac
                    ;;
                write)
                    if [ -n "$install_pid" ] && kill -0 "$install_pid" ;then
                        write_error "Process already running"
                        return
                    fi
                    do_install "$source_dir" "$target_dir"&
                    install_pid=$!
                    ;;
        esac
}

message_loop
