#!/bin/bash

IFS=$'\n'

print_modaliases() {
    declare class=$1 variants=$2 pos=$3
    if [ -n "$variants" ]; then
	echo "${class:0:pos}[$variants]${class:pos+1}"
    else
	[ -z "$class" ] || echo "$class"
    fi
}

combine_modaliases() {
    declare tag class variants pos n
    read class
    while read tag; do
	for ((n=0; n<${#class}; n++)); do
	    if [ "*" != "${class:n:1}" -a \
		 "${class:0:n}" = "${tag:0:n}" -a \
		 "${class:n+1}" = "${tag:n+1}" ] &&
	       ( [ -z "$pos" ] || [ $n = $pos ] ); then
		variants="${variants:-${class:n:1}}${tag:n:1}"
		pos=$n
		break
	    fi
	done
	if [ $n -eq ${#class} ]; then
	    print_modaliases "$class" "$variants" "$pos"
	    variants=
	    pos=
	    class=$tag
	fi
    done
    print_modaliases "$class" "$variants" "$pos"
}

# Encode all characters other than [*:a-zA-Z0-9] in stdin as %XX.
# (This includes the % character itself, which becomes %25.)
hexenc() {
    local line hex

    while read line; do
            set -- "" "$line"
            while [[ "$2" =~ ([*:a-zA-Z0-9]*)([^*:a-zA-Z0-9])(.*) ]]; do
                hex=$(echo -n "${BASH_REMATCH[2]}" | hexdump -e '"%X"')
                set -- "$1${BASH_REMATCH[1]}%$hex" "${BASH_REMATCH[3]}"
            done
            echo "$1$2"
    done
}

for module in $(grep -E '/lib/modules/.+\.ko(\.gz|\.xz|\.zst)?$' | grep -v '/lib/modules/[^/]*/kernel/'); do
    vermagic=$(/sbin/modinfo -F vermagic "$module")
    krel=${vermagic%% *}
    /sbin/modinfo -F alias "$module" \
    | hexenc \
    | sed -nre "s,(.+:.+),modalias(kernel-${krel##*-}:\\1),p"
done \
| sort -u \
| combine_modaliases
