#!/bin/sh

PROG="${0##*/}"
stage2=/root

message() {
	printf %s\\n "$PROG: $*"
}

# get /proc/cmdline parameter
# if key is specified, parse key1:value1,key2:value2... parameter argument
# and select the corresponding key value
# returns:
#       0 if there is a parameter (also print it's value if "-p" is used)
#       1 if there is no such parameter
get_cmdline() { # [-p] parameter [key]
  local SEDFLAG=""
  local SEARCH=""
  local REPLACE=""
  local CMDLINE="${PROC_CMDLINE:-/proc/cmdline}"

  case "$1" in
    -p) SEDFLAG="p"; shift ;;
  esac

  case "$#" in
    1) SEARCH="$1(=([^ ]*)|()( |$))"; REPLACE="\3";;
    *) SEARCH="$1=(.*,|)$2(:([^, ]+)|()(,.*| |\$))"; REPLACE="\4";;
  esac

  sed -nr "
  s/(^|.* )$SEARCH.*/$REPLACE/$SEDFLAG
  t
  q 1
  " < "$CMDLINE"
}

# check if get_cmdline -p $2 [$3] is equal to $1 pattern
equal_cmdline() {  # value <get_cmdline parameter> [<get_cmdline parameter2>]
  local V="$1"; shift
  case `get_cmdline -p "$@"` in
      $V) return 0;;
      *) return 1;;
  esac
}

nfs_overlays=''

nfs_slice() {
	equal_cmdline nfs automatic method || return

	local profile
	local parent_directory
	local overlays
	parent_directory="$(get_cmdline -p automatic directory)" && \
	parent_directory="${parent_directory%/?*}"
	overlays="$(get_cmdline -p automatic overlays)" || \
	overlays=${parent_directory:-/srv/public/netinst}/overlays-live

	# mount overlays from nfs
	ip=$(netstat -t -n | grep :2049 | head -n1 | \
		sed 's/  */ /g' | cut -d' ' -f5 | cut -d: -f1)
	profile=$(get_cmdline -p profile || : )
	mkdir -p $stage2/tmp/images
	message "Mounting NFS overlays from $ip:$overlays"
	if nfsmount -o nolock $ip:$overlays $stage2/tmp/images > /dev/null 2>&1 ; then
		local msg
		ls -l $stage2/tmp/images/ > /dev/null || :
		local images=$(find $stage2/tmp/images/$profile -maxdepth 1 \
			-name "*.iso" -o -name "*.squashfs" | sort)
		for image in $images ; do
			msg="${msg} $(basename "$image")"
			imgdir=$stage2/tmp/overlays/$(basename "$image")
			mkdir -p $imgdir
			mount -o loop $image $imgdir \
			&& nfs_overlays="$imgdir:$nfs_overlays"
		done
		test -n "$msg" && message "$msg" || \
		message "No overlays found for profile=$profile"
	else
		message "NFS mount failed"
	fi
}

debug() { get_cmdline propagator-debug && echo "DEBUG: $*" ||:; }

mount_options="noatime,nodiratime,barrier=0,delalloc"
mount_options="$mount_options,nobh,errors=remount-ro"
# "journal_async_commit,data=writeback" too if we used journal

mount_disk_slice() {
	debug "in mount_disk_slice()"
	[ -b "$1" ] || return
	get_cmdline live_rw || return
	mount -o $mount_options "$1" $stage2.rw
}

mkfs_opts="-O ^has_journal,sparse_super2 -E packed_meta_blocks=1,num_backup_sb=1"

create_disk_slice() {
	debug "in create_disk_slice()"
	[ -f /sys/dev/block/$(mountpoint -d /image)/partition ] || return 0
	[ -h /dev/disk/by-label/alt-live-storage ] && return 0
	[ -h /dev/disk/by-label/alt-slow-storage ] && return 1

	partition=$(mountpoint -d /image)
	major=${partition%:*}
	minor=$((${partition#*:}& ~0xf))
	devlink=$(readlink /sys/dev/block/$major:$minor)
	device=/dev/${devlink##*/}
	before=$(fdisk -l $device | grep "^$device" | wc -l)
	partpath=/sys/dev/block/$partition
	newstart=$(($(cat $partpath/start)+$(cat $partpath/size)+1))
	fdisk $device << _EOF_ 2>&1 | grep "^Created"
n
p

$newstart

w
_EOF_
	success=
	gb=$((2*1024*1024)) # sectors
	after=$(fdisk -l $device | grep "^$device" | wc -l)
	if [ $after -gt $before ] ; then 
		partline=$(fdisk -l $device | grep "^$device" | tail -n1)
		start=$(echo $partline | sed 's/  */ /g' | cut -d' ' -f2)
		length=$(($(echo $partline | sed 's/  */ /g' | cut -d' ' -f3)-$start))
		debug "in create_disk_slice(): length=$length"
		[ "$length" -ge "$gb" ] || return 1
		number=$(echo $partline | cut -d' ' -f1| sed 's/[^0-9]*//')
		partdev=$device$number
		udevd --daemon >/dev/null 2>&1
		addpart $device $number $start $length && udevadm trigger
		# wait for $device$number
		for n in seq 1 10; do
			[ -b $partdev ] && break
			sleep 1
		done
		{ time -f "%e" -o /mkfs.time \
			mke2fs -t ext4 $mkfs_opts \
			       -L alt-live-storage $partdev &&
			success=1; } 2>&1 | grep "^Filesystem label"
		mkfstime="$(tail -1 /mkfs.time | cut -f1 -d.)"
		debug "in create_disk_slice(): mkfstime=$mkfstime"
		# current timelimit is set to "< 1 second" by practice;
		# explicit RO/RW for refind as well would be a better fix
		if [ -d /sys/firmware/efi -a "$mkfstime" -gt 0 ]; then
			echo "Warning: slow flash, marking to avoid RW use"
			echo "(or run: e2label $partdev alt-live-storage)"
			e2label $partdev alt-slow-storage
			sleep 5
			success=
		fi
		debug "in create_disk_slice(): success=$success"
		#[ -n "$success" ] && mount_disk_slice $partdev
		udevadm trigger
		udevadm settle
		udevadm control --exit
	fi
}

# Automatic rw live on flash
# NB: may severely degrade performance due to heavier I/O
#     (especially for the first boot)
disk_slice(){
	debug "in disk_slice()"
	local dev=/dev/disk/by-label/alt-live-storage
	case "$(get_cmdline -p automatic method)" in
	disk|cdrom)
		if [ -d /sys/firmware/efi ] || get_cmdline automatic label; then
			create_disk_slice
		fi
		;;
	esac

	if [ -h $dev ]; then
		grep -qs "[[:space:]]$stage2.rw[[:space:]]" /proc/mounts ||
			mount_disk_slice $dev
	fi
}

#
# Entry point
#

echo; echo; echo

if cat /proc/mounts | grep "[[:space:]]$stage2[[:space:]]" | grep -s -q '[[:space:]]squashfs[[:space:]]'; then
    message "Root fs is squashfs"
    RO_ROOT="yes"
elif equal_cmdline live stagename; then
    message "Running live"
    RO_ROOT="yes"
elif equal_cmdline rescue stagename; then
    message "Running rescue"
    RO_ROOT="yes"
else
    message "Unknown root fs"
    RO_ROOT="no"
fi

if [ "$RO_ROOT" = "yes" ]; then
    message "Remounting / with Overlayfs"
    [ -L /etc/mtab ] || ln -sf /proc/mounts /etc/mtab
    /bin/mkdir -p $stage2.rw $stage2.ro
    if equal_cmdline live stagename || equal_cmdline rescue stagename; then
	    get_cmdline live_rw && disk_slice
    fi
    /bin/mountpoint -q $stage2.rw || /bin/mount -t tmpfs none $stage2.rw -o mode=755
    /bin/mkdir -p $stage2.rw/rw $stage2.rw/wk
    /bin/mount $stage2 $stage2.ro --move
    if equal_cmdline live stagename; then
	    nfs_slice
    fi
    mount -t overlay overlay -o lowerdir=$nfs_overlays$stage2.ro,upperdir=$stage2.rw/rw,workdir=$stage2.rw/wk $stage2
    /bin/mkdir -p $stage2/.ro $stage2/.rw
    /bin/mount $stage2.ro $stage2/.ro --move
    /bin/mount $stage2.rw $stage2/.rw --move
    /bin/rmdir $stage2.rw $stage2.ro

    message "Root FS overlayed with Overlayfs"
fi
    
if get_cmdline propagator-debug ; then
    /bin/openvt -s -w -- /bin/sh
fi
