#!/bin/bash -efu
# SPDX-License-Identifier: GPL-3.0-or-later

. shell-error
. shell-quote

UDEV_BUILTINS=()
readarray -t UDEV_BUILTINS <<< "$(
	"$UDEVADM" test-builtin --help 2>&1 >/dev/null |
		sed -nr -e 's/^[[:space:]]+([^[:space:]]+)[[:space:]]+.*$/\1/p' |
		sort -u
)"

FILES=()
put_file()
{
	local a
	for a in "${FILES[@]}"; do
		[ "$1" != "$a" ] || return 0
	done
	FILES+=("$1")
}

is_builtin()
{
	local a
	for a in "${UDEV_BUILTINS[@]}"; do
		[ "$a" != "$1" ] || return 0
	done
	return 1
}

parse_command()
{
	local rule hint cmd args arg path

	rule="$1"; shift
	hint="$1"; shift

	quote_shell_args args "$1"
	eval "set -- $args"

	cmd=
	for arg; do
		case "$arg" in
			'$'*)
				if [ -z "${arg##*/*}" ] && [ -n "${arg##*=*}" ]; then
					arg="${arg##*/}"
				else
					continue
				fi
				;;
			[A-Za-z_]*=*)
				continue
				;;
			-*|%*)
				break
				;;
		esac

		cmd="$arg"
		break
	done

	[ -n "$cmd" ] ||
		return 0

	if [ -z "${cmd##/*}" ]; then
		# Absolute path is given.
		if [ ! -e "$cmd" ]; then
			verbose "utility not found: $cmd"
			return 0
		fi
		verbose "add $cmd"
		put_file "$cmd"
		return 0
	fi

	case "$rule" in
		program)
			;;
		run)
			case "$hint" in
				builtin)
					! is_builtin "$cmd" ||
						return 0
					;;
			esac
			;;
		import)
			case "$hint" in
				file)
					verbose "it's not obvious where to look for '$cmd'"
					;;
				program|builtin)
					! is_builtin "$cmd" ||
						return 0
					;;
			esac
			;;
		*)
			;;
	esac

	local PATH="/lib/udev:$PATH"

	# Search external command
	if path=$(type -P "$cmd" 2>/dev/null); then
		verbose "add $path"
		put_file "$path"
		return 0
	fi

	verbose "command not found: $cmd"
}

while IFS=$'\t' read -r file rule attr cmd; do
	[ -n "$cmd" ] ||
		continue

	# Skip initramfs-only wrappers for real command.
	# shellcheck disable=SC2043
	for w in /bin/udev-run; do
		if [ -z "${cmd##$w *}" ]; then
			cmd="${cmd#$w }"
			break
		fi
	done

	verbose "$rule{$attr} = $cmd"
	parse_command "$rule" "$attr" "$cmd"
done < <(udev-rules -x "$1")

for a in "${FILES[@]}"; do
	printf '%s\n' "$a"
done
