diff --git a/completions/cryptsetup b/completions/cryptsetup index dbe2a2cd80c..3ade169b900 100644 --- a/completions/cryptsetup +++ b/completions/cryptsetup @@ -10,6 +10,51 @@ _comp_cmd_cryptsetup__device() _comp_compgen -c "${cur:-/dev/}" filedir } +_comp_cmd_cryptsetup__action() +{ + local REPLY IFS=$' \t\n' + _comp_dequote "${1-}" || return 1 + local cmd=${REPLY:-cryptsetup} + local -a actions + _comp_split -l actions "$( + { + LC_ALL=C "$cmd" --help 2>&1 | + sed -n '/^ is one of:/,/^[^[:space:]]/s/^[[:space:]]\{1,\}\([^[:space:]]\{1,\}\).*/\1/p' + LC_ALL=C man cryptsetup 2>&1 | + awk '/^[[:space:]]+[[:alnum:]_]+([[:space:]]+(-[^[:space:].]+|<[^<>]+>|\[[^][]+\]|or))*$/ {print $1}' + } | sort -u + )" + + if ((${#actions[@]} == 0)); then + # The fallback action list is extracted from the following source: + # https://gitlab.com/cryptsetup/cryptsetup/-/blob/main/src/cryptsetup.c#L3154-3208 (search for "Handle aliases") + # https://gitlab.com/cryptsetup/cryptsetup/-/blob/main/src/cryptsetup.c#L2831-2867 (search for "struct action_type") + # https://gitlab.com/cryptsetup/cryptsetup/-/blob/main/src/cryptsetup_args.h#L28-53 (see the macros "*_ACTION") + actions=(benchmark bitlkClose bitlkDump bitlkOpen close config convert + create erase isLuks loopaesClose loopaesOpen luksAddKey + luksChangeKey luksClose luksConfig luksConvertKey luksDump + luksErase luksFormat luksHeaderBackup luksHeaderRestore + luksKillSlot luksOpen luksRemoveKey luksResume luksSuspend luksUUID + open plainClose plainOpen reencrypt refresh remove repair resize + status tcryptClose tcryptDump tcryptOpen token) + + # We attempt to filter the supported actions by the strings in the binary. + local path + if path=$(type -P -- "$cmd" 2>/dev/null || type -P -- cryptsetup 2>/dev/null); then + local filtering_pattern + printf -v filtering_pattern '%s\n' "${actions[@]}" + filtering_pattern=${filtering_pattern%$'\n'} + + local filtered_actions + filtered_actions=$(strings "$path" | command grep -Fx "$filtering_pattern" | sort -u) && + [[ $filtered_actions ]] && + _comp_split -l actions "$filtered_actions" + fi + fi + + _comp_compgen -- -W '"${actions[@]}"' +} + _comp_cmd_cryptsetup() { local cur prev words cword was_split comp_args @@ -91,10 +136,7 @@ _comp_cmd_cryptsetup() _comp_compgen_help [[ ${COMPREPLY-} == *= ]] && compopt -o nospace else - _comp_compgen -- -W 'open close resize status benchmark repair - erase luksFormat luksAddKey luksRemoveKey luksChangeKey - luksKillSlot luksUUID isLuks luksDump tcryptDump luksSuspend - luksResume luksHeaderBackup luksHeaderRestore' + _comp_cmd_cryptsetup__action "$1" fi fi diff --git a/test/t/test_cryptsetup.py b/test/t/test_cryptsetup.py index fdc981b8dcb..d3fa9fb055d 100644 --- a/test/t/test_cryptsetup.py +++ b/test/t/test_cryptsetup.py @@ -9,3 +9,11 @@ def test_1(self, completion): @pytest.mark.complete("cryptsetup -", require_cmd=True) def test_2(self, completion): assert completion + + @pytest.mark.complete( + "cryptsetup luksE", + require_cmd=True, + skipif=r'! { cryptsetup --help; man cryptsetup; } 2>/dev/null | command grep -qE "(^|[[:space:]])luksErase([[:space:]]|\$)"', + ) + def test_github_issue758(self, completion): + assert completion == "rase"