# -*- shell-script -*- vim:ft=sh:
#---------------------------------------------------------------------
# Description: Mount Ubuntu Core root filesystem and userdata partition.
# Entry point: mountroot().
#---------------------------------------------------------------------

pre_mountroot()
{
	local script_dir="/scripts/local-top"
	[ "$quiet" != "y" ] && log_begin_msg "Running $script_dir"
	run_scripts "$script_dir"
	[ "$quiet" != "y" ] && log_end_msg
}

sync_dirs()
{
	base=$1
	source=$2
	target=$3

	OLD_PWD="$PWD"
	cd "$base"

	for file in "$source"/*
	do
		# Skip empty directories
		[ ! -e "$base/$file" ] && continue

		# If the target already exists as a file or link, there's nothing we can do
		[ -e "$target/$file" -o -L "$target/$file" ] && [ ! -d "$target/$file" ] && continue

		# If the target doesn't exist, just copy it over
		if [ ! -e "$target/$file" -a ! -L "$target/$file" ]; then
			cp -Ra "$base/$file" "$target/$file"
			continue
		fi

		# That leaves us with directories and a recursive call
		[ -d "$file" ] && sync_dirs "$base" "$file" "$target"
	done

	cd "$OLD_PWD"
}

# Determine full path to disk partition given a filesystem label.
get_partition_from_label()
{
	local label="$1"

	[ -n "$label" ] || panic "need FS label"

	local part=$(find /dev -name "$label"|tail -1)
	[ -z "$part" ] && return
	local path=$(readlink -f "$part")
	[ -n "$path" ] && echo "$path"
}

# Process the list of bind-mounts (but don't mount them - systemd will handle that)
handle_writable_paths()
{
	writable_paths="$1"
	fstab="$2"

	[ -n "$writable_paths" ] || panic "need writeable paths"
	[ -e "$writable_paths" ] || panic "writeable paths does not exist"
	[ -n "fstab" ] || panic "need fstab"

 	cat "$writable_paths" | while read line; do
		# tokenise
 		set -- $line

 		# skip invalid/commented entries
 		([ -z "$1" ] || \
		 [ -z "$2" ] || \
		 [ -z "$3" ] || \
		 [ -z "$4" ] || \
		 [ -z "$5" ]) && continue

		# ignore comments
 		[ "$1" = "#" ] && continue
 
 		# skip invalid mount points
 		dstpath="${rootmnt}/$1"
 		[ ! -e "$dstpath" ] && continue

 		if [ "$3" = "temporary" ]; then
 			# Temporary entries are simple, just mount a tmpfs
 			echo "tmpfs $1 tmpfs $5 0 0" >> "$fstab"
 		elif [ "$3" = "persistent" ] || \
		     [ "$3" = "synced" ]; then
 			# Figure out the source path
 			if [ "$2" = "auto" ]; then
 				srcpath="${rootmnt}/userdata/system-data/$1"
 				path="/userdata/system-data/$1"
 			else
 				srcpath="${rootmnt}/userdata/$2"
 				path="/userdata/$2"
 			fi
 
 			if [ ! -e "$srcpath" ]; then
 				# Process new persistent or synced paths
 				dstown=$(stat -c "%u:%g" "$dstpath")
 				dstmode=$(stat -c "%a" "$dstpath")
 				mkdir -p ${srcpath%/*}
 				if [ ! -d "$dstpath" ]; then
 					# Deal with redirected files
 					if [ "$4" = "transition" ]; then
 						cp -a "$dstpath" "$srcpath"
 					else
 						touch "$srcpath"
 						chown "$dstown" "$srcpath"
 						chmod "$dstmode" "$srcpath"
 					fi
 				else
 					# Deal with redirected directories
 					if [ "$4" = "transition" ] || [ "$3" = "synced" ]; then
 						cp -aR "$dstpath" "$srcpath"
 					else
 						mkdir "$srcpath"
 						chown "$dstown" "$srcpath"
 						chmod "$dstmode" "$srcpath"
 					fi
 				fi
 			elif [ "$3" = "synced" ]; then
 				# Process existing synced paths
 				sync_dirs "$dstpath" . "$srcpath"
 			fi
 
 			# Write the fstab entry
 			if [ "$5" = "none" ]; then
 				echo "$path $1 none bind 0 0" >> "$fstab"
			else
 				echo "$path $1 none bind,$5 0 0" >> "$fstab"
 			fi
 		else
 			continue
 		fi
 	done
}

#---------------------------------------------------------------------
# XXX: Entry point - called by the initramfs "/init" script.
#---------------------------------------------------------------------
mountroot()
{
	local rootfs_label="system-data"
	local userdata_label="user-data"

	local userdata_mnt="/tmpmnt_${userdata_label}"

	pre_mountroot

	[ "$quiet" != "y" ] && log_begin_msg "Running /scripts/local-premount"
	run_scripts /scripts/local-premount
	[ "$quiet" != "y" ] && log_end_msg

	# Make sure the device has been created by udev before we try to mount
	udevadm settle

	path=$(get_partition_from_label "$rootfs_label")

	[ -n "$path" ] || panic "cannot find '$rootfs_label' partition"

	# Override with a possible cmdline parameter
	if grep -q datapart= /proc/cmdline; then
		for x in $(cat /proc/cmdline); do
			case "${x}" in
			datapart=*)
				path="${x#*=}"
				;;
			esac
		done
	fi

	# Mount the root filesystem read-only.
	echo "initrd: mounting $path" >/dev/kmsg || true
	mount -o defaults,ro "$path" "$rootmnt"

	# Create a read-only bind mount on top of the already read-only
	# FS. This is to stop the system from noticing when the root
	# filesystem is made writable (when system updates are applied).
	mount -o bind,ro "$rootmnt" "$rootmnt"

	mkdir -p "$userdata_mnt"

	path=$(get_partition_from_label "$userdata_label")

	[ -n "$path" ] || panic "cannot find '$userdata_label' partition"

	# Mount the userdata partition to a temporary mount point
	echo "initrd: mounting $userdata_label partition" >/dev/kmsg || true
	mount -o discard "$path" "$userdata_mnt"
	mount --move "$userdata_mnt" "${rootmnt}/userdata"

	echo "initrd: mounting /run" >/dev/kmsg || true
	mount -o rw,nosuid,noexec,relatime,mode=755 -t tmpfs tmpfs "${rootmnt}/run"

	# Prepare the fstab
	fstab="${rootmnt}/etc/fstab"
 	writable_paths="${rootmnt}/etc/system-image/writable-paths"

	# Add writable overlays
	if [ -e "$writable_paths" ]; then
		touch "${rootmnt}/run/image.fstab"
		mount -o bind "${rootmnt}/run/image.fstab" "$fstab" || panic "Cannot bind mount fstab"
		echo "/dev/root / rootfs defaults,ro 0 0" >> "$fstab"

		handle_writable_paths "$writable_paths" "$fstab"
	fi

	# Apply customized content
	for user in "${rootmnt}"/userdata/user-data/*
	do
		if [ -d "${rootmnt}/custom/home" ] && [ ! -e "$user/.customized" ]; then
			echo "initrd: copying custom content tp " >/dev/kmsg || true
			cp -Rap "${rootmnt}"/custom/home/* "$user/"
			cp -Rap "${rootmnt}"/custom/home/.[a-zA-Z0-9]* "$user/"
			touch "$user/.customized"
			dstown=$(stat -c "%u:%g" "$user")
			chown -R "$dstown" "$user/"
		fi
	done

	[ "$quiet" != "y" ] && log_begin_msg "Running /scripts/local-bottom"
	run_scripts /scripts/local-bottom
	[ "$quiet" != "y" ] && log_end_msg
}
