#!/bin/dash
#
# Emit udisks2-oriented KEY=value lines into $VDEV_METADATA/<basename> for
# SUBSYSTEM=block.  event_generate_text() in subr-event.sh cats that file before
# DEVLINKS/TAGS/properties (see udisks2.act, lexicographically before zzz-udev-compat).
#
# Optional environment (from action VAR_* keys, exported as VDEV_VAR_*):
#   VDEV_VAR_UDISKS_PROPS_BASENAME   Output file basename only (default udisks-props).
#                                    Recorded under $VDEV_METADATA/.vdev-udisks-props-basename
#                                    so subr-event.sh picks the same name without duplicating config.
#
# With daemonlet=true, vdevd runs this via the daemonlet runner: main() is called
# once per device stanza (stdin env + "done"); otherwise main runs once and exits.
#

. "$VDEV_HELPERS/subr.sh"

# $1  property name (VDEV_PART_* as written by disk.sh)
vdev_metadata_prop() {
	_props="$VDEV_METADATA/properties"
	_key="$1"

	[ -f "$_props" ] || return 1
	grep "^${_key}=" "$_props" 2>/dev/null | head -1 | cut -d= -f2-
}

# Mirror the partition-type ignores from /lib/udev/rules.d/80-udisks2.rules, plus
# MBR extended/container types (0x05/0x0f/0x85).  Without this, a 1-sector/1K
# extended-partition node is exported as UDISKS_IGNORE=0 and can break udisks2/gvfs
# presentation of the real logical volumes on the same disk.
udisks_ignore_special_partition() {
	_scheme=""
	_ptype=""

	_scheme="$(vdev_metadata_prop VDEV_PART_ENTRY_SCHEME)"
	_ptype="$(vdev_metadata_prop VDEV_PART_ENTRY_TYPE)"
	[ -n "$_scheme" ] && [ -n "$_ptype" ] || return 1

	if udisks_is_hybrid_iso_partition; then
		return 1
	fi

	case "$_scheme" in
	dos)
		case "$_ptype" in
		0x05|0x5|0x0f|0xf|0x85)
			return 0
			;;
		0x0|0x11|0x12|0x14|0x16|0x17|0x1b|0x1c|0x1e|0x27|0x3d|0x84|0x8d|0x8e|0x90|0x91|0x92|0x93|0x97|0x98|0x9a|0x9b|0xab|0xbb|0xc2|0xc3|0xdd|0xef|0xfd)
			return 0
			;;
		esac
		;;
	gpt|GPT)
		case "$(echo "$_ptype" | tr '[:upper:]' '[:lower:]')" in
		c12a7328-f81f-11d2-ba4b-00a0c93ec93b|\
		21686148-6449-6e6f-744e-656564454649|\
		a19d880f-05fc-4d3b-a006-743f0f84911e|\
		e6d6d379-f507-44c2-a23c-238f2a3df928|\
		e3c9e316-0b5c-4db8-817d-f92df00215ae|\
		de94bba4-06d1-4d40-a16a-bfd50179d6ac|\
		bc13c2ff-59e6-4262-a352-b275fd6f7172)
			return 0
			;;
		esac
		;;
	esac

	return 1
}

# Optical drives (sr*) and superfloppy USB sticks are whole block devices
# (DEVTYPE=disk) but must remain visible to udisks2/gvfs.
udisks_is_optical() {
	echo "$VDEV_OS_DEVNAME" | /bin/egrep -q 'sr[0-9]'
}

udisks_block_removable() {
	_sysfs=""

	if [ -n "$VDEV_OS_SYSFS_MOUNTPOINT" ] && [ -n "$VDEV_OS_DEVPATH" ]; then
		_sysfs="$VDEV_OS_SYSFS_MOUNTPOINT/$VDEV_OS_DEVPATH"
	elif [ -n "$VDEV_OS_DEVNAME" ]; then
		_base="$(echo "$VDEV_OS_DEVNAME" | /bin/sed 's/[0-9]*$//')"
		_sysfs="/sys/block/$_base"
	fi

	[ -f "$_sysfs/removable" ] && [ "$(/bin/cat "$_sysfs/removable" 2>/dev/null)" = "1" ]
}

# 80-udisks2.rules shows hybrid ISO installer sticks even though 0x0/0x17 are
# otherwise special-cased.
udisks_is_hybrid_iso_partition() {
	_scheme=""
	_ptype=""
	_partnum=""
	_fstype=""

	_scheme="$(vdev_metadata_prop VDEV_PART_ENTRY_SCHEME)"
	_ptype="$(vdev_metadata_prop VDEV_PART_ENTRY_TYPE)"
	_partnum="$(vdev_metadata_prop VDEV_PART_ENTRY_NUMBER)"
	_fstype="$(vdev_metadata_prop VDEV_FS_TYPE)"

	[ "$_scheme" = "dos" ] || return 1
	case "$_ptype" in
	0x0|0x17) ;;
	*) return 1 ;;
	esac
	case "$_partnum" in
	1|2) ;;
	*) return 1 ;;
	esac
	case "$_fstype" in
	iso9660|udf) return 0 ;;
	esac

	return 1
}

# Debian installer comments before UUID= fstab lines, e.g.:
#   # / was on /dev/sda1 during installation
# Echo the install-time device name (sda1) for $1 filesystem UUID, or nothing.
udisks_fstab_install_dev_for_uuid() {
	_uuid="$1"
	_comment=""
	_line=""
	_fstab_uuid=""
	_uuid_cmp=""
	_install=""

	[ -n "$_uuid" ] && [ -r /etc/fstab ] || return 0

	_uuid_cmp="$(echo "$_uuid" | tr '[:upper:]' '[:lower:]')"

	while IFS= read -r _line || [ -n "$_line" ]; do
		case "$_line" in
		"#"* )
			_comment="$_line"
			;;
		""|*"#"*)
			;;
		*)
			_fstab_uuid="$(echo "$_line" | sed -n 's/.*UUID=\([^[:space:]]*\).*/\1/p' | tr '[:upper:]' '[:lower:]')"
			if [ -n "$_fstab_uuid" ] && [ "$_fstab_uuid" = "$_uuid_cmp" ]; then
				_install="$(echo "$_comment" | sed -n 's#.*[Ww]as on /dev/\([^[:space:]]*\).*#\1#p')"
				if [ -n "$_install" ]; then
					echo "$_install"
					return 0
				fi
			fi
			_comment=""
			;;
		esac
	done < /etc/fstab

	return 0
}

# UUID listed in fstab: only the install-time device is treated as the system
# volume; other nodes with the same UUID (Clonezilla clones) stay visible.
udisks_apply_fstab_clone_policy() {
	_uuid="$1"
	_devname="$2"
	_install=""

	[ -n "$_uuid" ] && [ -n "$_devname" ] || return 0

	_install="$(udisks_fstab_install_dev_for_uuid "$_uuid")"
	[ -n "$_install" ] || return 0

	if [ "$_install" = "$_devname" ]; then
		echo 1
	else
		echo 0
	fi
}

main() {

	if [ -z "$VDEV_METADATA" ] || [ ! -d "$VDEV_METADATA" ]; then
		return 0
	fi

	if [ "$VDEV_OS_SUBSYSTEM" != "block" ]; then
		return 0
	fi

	_BN="${VDEV_VAR_UDISKS_PROPS_BASENAME:-udisks-props}"
	case "$_BN" in
	*/*|*..*|""|"."|"..")
		_BN=udisks-props
		;;
	esac

	# Tell event_generate_text() which basename to cat (same metadata dir, this event).
	printf '%s\n' "$_BN" > "$VDEV_METADATA/.vdev-udisks-props-basename"

	_UDF="$VDEV_METADATA/$_BN"

	: > "$_UDF"

	_BLOCK_DEV=""
	if [ -n "$VDEV_OS_DEVNAME" ]; then
		_BLOCK_DEV="$VDEV_MOUNTPOINT/$VDEV_OS_DEVNAME"
	fi

	if [ -n "$_BLOCK_DEV" ] && [ -e "$_BLOCK_DEV" ]; then
		_SIZE="$($VDEV_HELPERS/vdev_block_info -S -D $_BLOCK_DEV)"
		_IGNORE=0
		_UUID=""
		_FSTAB_POLICY=""

		if [ "$_SIZE" = "0" ] && ! udisks_is_optical; then
			_IGNORE=1
		elif [ "$VDEV_OS_DEVTYPE" = "disk" ]; then
			if udisks_is_optical || udisks_block_removable; then
				# sr* and superfloppy/removable USB media are mountable
				# whole devices; fixed internal disks stay hidden.
				_IGNORE=0
			else
				_IGNORE=1
			fi
		elif udisks_ignore_special_partition; then
			_IGNORE=1
		fi

		_BLKID="$(vdev_blkid "$_BLOCK_DEV")"
		if [ $? -eq 0 ] && [ -n "$_BLKID" ]; then
			UUID=""
			eval "$_BLKID"
			_UUID="$UUID"
			if [ -n "$_UUID" ]; then
				_FSTAB_POLICY="$(udisks_apply_fstab_clone_policy "$_UUID" "$VDEV_OS_DEVNAME")"
				case "$_FSTAB_POLICY" in
				0)
					# Same UUID as an /etc/fstab entry, but not the install device.
					_IGNORE=0
					;;
				1)
					# Canonical install-time device for this fstab UUID.
					_IGNORE=1
					;;
				esac
			fi
		fi

		if [ "$_IGNORE" -eq 1 ]; then
			echo "UDISKS_IGNORE=1" >> "$_UDF"
		else
			echo "UDISKS_IGNORE=0" >> "$_UDF"
			_LABEL="$($VDEV_HELPERS/vdev_block_info -L -D $_BLOCK_DEV)"
			if [ -z "$_LABEL" ]; then
				_BLOCK_INFO=" -- $_SIZE"
			else
				_BLOCK_INFO=" - $_LABEL - $_SIZE"
				echo "VDEV_FS_LABEL=$_LABEL" >> "$_UDF"
				echo "VDEV_FS_LABEL_ENC=$_LABEL" >> "$_UDF"
			fi
			echo "UDISKS_CAN_POWER_OFF=1" >> "$_UDF"
			echo "UDISKS_NAME=$VDEV_OS_DEVNAME $_BLOCK_INFO" >> "$_UDF"
			if [ -n "$_UUID" ]; then
				echo "VDEV_FS_UUID=$_UUID" >> "$_UDF"
				echo "VDEV_FS_UUID_ENC=$_UUID" >> "$_UDF"
			fi
		fi
	else
		echo "UDISKS_IGNORE=1" >> "$_UDF"
	fi

	return 0
}

if [ "${VDEV_DAEMONLET:-0}" -eq 0 ]; then
	main
	exit $?
fi
