#!/bin/bash
#================
# FILE          : livestick
#----------------
# PROJECT       : openSUSE Build-Service
# COPYRIGHT     : (c) 2013 SUSE LINUX Products GmbH, Germany
#               :
# AUTHOR        : Marcus Schaefer <ms@suse.de>
#               :
# BELONGS TO    : Operating System images
#               :
# DESCRIPTION   : helper tool to deploy kiwi live iso image on a
#               : USB stick without removing data from the stick
#               :
# STATUS        : Work-In-Progress
#----------------
#==========================================
# pre-checks
#------------------------------------------
if [ -z "$1" ] || [ -z "$2" ];then
    echo "Usage: livestick kiwi-live.iso /dev/stick"
    exit 1
fi

isoinfo=/usr/bin/isoinfo
if [ ! -x $isoinfo ]; then
   isoinfo=/usr/lib/genisoimage/isoinfo
fi
if [ ! -x $isoinfo ];then
    echo "Can't find isoinfo in /usr/bin or /usr/lib/genisoimage"
    exit 1
fi

#==========================================
# Functions
#------------------------------------------
. /usr/share/kiwi/modules/KIWILinuxRC.sh

#==========================================
# Functions
#------------------------------------------
function clean {
    umount /mnt &>/dev/null
    if [ -d "$tmpdir" ];then
        rm -rf $tmpdir
    fi
    exit 1
}

#==========================================
# Signal handling
#------------------------------------------
trap clean INT TERM

#==========================================
# set default theme
#------------------------------------------
basetheme=upstream

#==========================================
# get disk-by-id device name first
#------------------------------------------
disk=$2
signature=$(blkid $disk -s TYPE -o value 2>/dev/null)
if [ ! -z "$signature" ] && [ ! "$signature" = "iso9660" ];then
    echo "Found filesystem signature $signature on $disk"
    echo "Need a stick disk device not a partition"
    clean
fi
kiwi_devicepersistency=by-uuid
device_disk=$(getDiskID $disk)
device_part=$(getDiskID $(ddn $(dn $device_disk) 1))
if [ ! -e "$device_disk" ];then
    echo "Can't find disk for $disk"
    clean
fi
if [ ! -e "$device_part" ];then
    echo "Can't find partition $device_part for $disk"
    clean
fi

#==========================================
# check if iso file exists
#------------------------------------------
image=$1
image_base=$(basename $image)
if [ ! -e $image ];then
    echo "Can't find OS image"
    clean
fi
#==========================================
# check if file is a kiwi live iso
#------------------------------------------
if ! $isoinfo -l -i $image 2>/dev/null | grep -q LIVEBOOT;then
    echo "Can't find live iso signature"
    echo "Make sure the given kiwi image file is of type: image=iso"
    clean
fi

#==========================================
# create tmp directory
#------------------------------------------
tmpdir=$(mktemp -q -d /tmp/kiwi-livestick.XXXXXX)
if [ ! -d $tmpdir ];then
    echo "Can't create tmpdir"
    clean
fi
mkdir -p $tmpdir/boot/grub2

#==========================================
# unpack grub2 theme tarball into a tmpdir
#------------------------------------------
echo "==> Preparation in progress..."
theme=/usr/share/kiwi/livestick/theme/$basetheme/booting.tgz
if ! tar -C $tmpdir/boot/grub2 -xf $theme;then
    echo "Can't extract grub2 theme files"
    clean
fi

#==========================================
# unpack boot helpers, bootnext, memcheck
#------------------------------------------
tools=/usr/share/kiwi/livestick/theme/$basetheme/tooling.tgz
if ! tar -C $tmpdir/boot -xf $tools; then
    echo "Can't extract boot helper files"
    clean
fi

#==========================================
# hard link grub2 stages
#------------------------------------------
if [ ! -d /boot/grub2/i386-pc ];then
    echo "Can't find grub2(i386-pc) on this system"
    clean
fi
cp -a /boot/grub2/i386-pc $tmpdir/boot/grub2

#==========================================
# create device.map file
#------------------------------------------
echo "(hd0) $device_disk" > $tmpdir/boot/grub2/device.map

#==========================================
# create grub2 prefix boot file
#------------------------------------------
uuid=$(blkid -o value -s UUID $device_part)
conf=$tmpdir/boot/grub2/bootpart.cfg
echo "search --no-floppy --fs-uuid --set=root $uuid" > $conf
echo 'set prefix=($root)/boot/grub2'   >> $conf

#==========================================
# create grub configuration
#------------------------------------------
conf=$tmpdir/boot/grub2/grub.cfg
arch=x86_64
if ! $isoinfo -p -i $image | grep -q X86_64;then
    arch=i386
    title=$(echo $image_base | sed -e s@\.i.86.*@@)
else
    title=$(echo $image_base | sed -e s@\.x86_64.*@@)
fi
cmdline_std="isofrom_device=$device_part"
cmdline_std="$cmdline_std isofrom_system=/boot/$image_base"
cmdline_std="$cmdline_std kiwi_cowdevice=$device_part"
cmdline_std="$cmdline_std kiwi_cowsystem=/boot/cowfile"
cmdline_std="$cmdline_std kiwi_hybridpersistent=true splash=silent"
cmdline_std="$cmdline_std ramdisk_size=512000 ramdisk_blocksize=4096"

cmdline_fsf="$cmdline_std ide=nodma apm=off noresume edd=off powersaved=off"
cmdline_fsf="$cmdline_fsf nohz=off highres=off processor.max+cstate=1"
cmdline_fsf="$cmdline_fsf nomodeseet x11failsafe"

cat > $conf << EOF
search --no-floppy --fs-uuid --set=root $uuid
set default=0
set font=/boot/grub2/fonts/unicode.pf2
if loadfont \$font ;then
        set gfxmode=auto
        insmod gfxterm
        insmod gfxmenu
        if terminal_output gfxterm; then true; else
                terminal gfxterm
        fi
fi
if loadfont /boot/grub2/themes/$basetheme/ascii.pf2;then
        loadfont /boot/grub2/themes/$basetheme/DejaVuSans-Bold14.pf2
        loadfont /boot/grub2/themes/$basetheme/DejaVuSans10.pf2
        loadfont /boot/grub2/themes/$basetheme/DejaVuSans12.pf2
        loadfont /boot/grub2/themes/$basetheme/ascii.pf2
        set theme=/boot/grub2/themes/$basetheme/theme.txt
        background_image -m stretch /boot/grub2/themes/$basetheme/background.png
fi
set timeout=10
menuentry "$title" --class os {
    set gfxpayload=auto
        echo Loading live system...
        loopback loop /boot/$image_base
    echo Loading linux...
        linux (loop)/boot/$arch/loader/linux $cmdline_std
    echo Loading initrd...
        initrd (loop)/boot/$arch/loader/initrd
}
menuentry "Failsafe -- $title" --class os {
    set gfxpayload=auto
        echo Loading live system...
        loopback loop /boot/$image_base
        echo Loading linux...
        linux (loop)/boot/$arch/loader/linux $cmdline_fsf
        echo Loading initrd...
        initrd (loop)/boot/$arch/loader/initrd
}
menuentry "Boot from Hard Disk" --class os {
        set root=(hd1)
        chainloader +1
}
menuentry "Memory Test" --class os {
        linux16 /boot/memtest
}
EOF

#==========================================
# hard link image
#------------------------------------------
if ! cp -l $image $tmpdir/boot;then
    echo "Can't copy image"
    clean
fi

#==========================================
# create grub2 core image
#------------------------------------------
format=i386-pc
biosmod="biosdisk part_msdos ext2 iso9660 chain gettext"
biosmod="$biosmod normal linux echo vga vbe png"
biosmod="$biosmod video_bochs video_cirrus gzio"
biosmod="$biosmod multiboot search configfile fat ntfs"
core=$tmpdir/boot/grub2/$format/core.img
bootconf=$tmpdir/boot/grub2/bootpart.cfg
if ! grub2-mkimage -O $format -o $core -c $bootconf $biosmod &>/dev/null;then
    echo "Can't create core boot image"
    clean
fi

#==========================================
# create cow file space
#------------------------------------------
if ! qemu-img create $tmpdir/boot/cowfile 500M &>/dev/null;then
    echo "Can't create cow file"
    clean
fi

#==========================================
# mount stick partition nr 1
#------------------------------------------
echo "==> Mounting stick..."
if ! mount $device_part /mnt;then
    echo "Can't mount target device"
    clean
fi

#==========================================
# sync tmpdir to / on the stick
#------------------------------------------
if ! rsync -rltvh --progress --modify-window=1 --delete $tmpdir/* /mnt;then
    echo "Can't rsync data to target"
    umount /mnt
    clean
fi

#==========================================
# install grub2 on stick
#------------------------------------------
stages=/mnt/boot/grub2/$format
devmap=/mnt/boot/grub2/device.map
if ! sfdisk $device_disk --force -A 1;then
    echo "Can't set first partition active"
    umount /mnt
    clean
fi
if ! grub2-bios-setup -f -d $stages -m $devmap $device_disk &>/dev/null;then
    echo "Can't install grub2 into MBR"
    umount /mnt
    clean
fi

echo "==> Umount..."
umount /mnt
clean
