diff options
author | Crestez Dan Leonard <cdleonard@gmail.com> | 2010-02-15 15:36:58 +0200 |
---|---|---|
committer | Crestez Dan Leonard <cdleonard@gmail.com> | 2010-02-15 15:36:58 +0200 |
commit | f294219990569082b20e08643b6e46256ca0862f (patch) | |
tree | 9426e8a90184135ac6303a5e1dde957815962052 | |
parent | 72a8cb5b49ad222e74f1d97ad10f85e3a002cf38 (diff) | |
parent | 91f7e8274e90632c95527bf0fc1407e9abd0b539 (diff) | |
download | bash-completion-f294219990569082b20e08643b6e46256ca0862f.tar.gz |
Merge branch 'mount-fix'
Fix mount handling of escapes (Alioth: #311410, Launchpad: #219971)
Conflicts:
CHANGES
-rw-r--r-- | CHANGES | 1 | ||||
-rw-r--r-- | contrib/mount | 86 | ||||
-rw-r--r-- | test/fixtures/mount/test-fstab | 24 | ||||
-rw-r--r-- | test/lib/completions/mount.exp | 85 |
4 files changed, 188 insertions, 8 deletions
@@ -71,6 +71,7 @@ bash-completion (2.x) * Fix completion of usernames (Alioth: #311396, Debian: #511788). * Fix chown test crashing on systems with no root group (Alioth: #312306). * Fixed tests when BASH_COMPLETION or TESTDIR contain spaces. + * Fix mount handling of escapes (Alioth: #311410, Launchpad: #219971). [ Raphaƫl Droz ] * Add xsltproc completion (Alioth: #311843). diff --git a/contrib/mount b/contrib/mount index 1f0d8a4a..0c7fad83 100644 --- a/contrib/mount +++ b/contrib/mount @@ -7,6 +7,74 @@ have mount && { +# Just like COMPREPLY=(`compgen -W "${COMPREPLY[*]}" -- "$cur"`), only better! +# +# This will correctly escape special characters in COMPREPLY. +_reply_compgen_array() +{ + # Create the argument for compgen -W by escaping twice. + # + # One round of escape is because we want to reply with escaped arguments. A + # second round is required because compgen -W will helpfully expand it's + # argument. + local i wlist + for i in ${!COMPREPLY[*]}; do + local q=$(quote "$(printf %q "${COMPREPLY[$i]}")") + wlist+=$q$'\n' + done + + # We also have to add another round of escaping to $cur. + local ecur="$cur" + ecur="${ecur//\\/\\\\}" + ecur="${ecur//\'/\'}" + + # Actually generate completions. + local oldifs=$IFS + IFS=$'\n' eval 'COMPREPLY=(`compgen -W "$wlist" -- "${ecur}"`)' + IFS=$oldifs +} + +# Unescape strings in the linux fstab(5) format (with octal escapes). +__linux_fstab_unescape() { + eval $1="'${!1//\'/\047}'" + eval $1="'${!1/%\\/\\\\}'" + eval "$1=$'${!1}'" +} + +# Complete linux fstab entries. +# +# Reads a file from stdin in the linux fstab(5) format; as used by /etc/fstab +# and /proc/mounts. +_linux_fstab() +{ + COMPREPLY=() + + # Read and unescape values into COMPREPLY + local fs_spec fs_file fs_other + local oldifs="$IFS" + while read -r fs_spec fs_file fs_other; do + if [[ $fs_spec = [#]* ]]; then continue; fi + if [[ $1 == -L ]]; then + local fs_label=${fs_spec/#LABEL=} + if [[ $fs_label != "$fs_spec" ]]; then + __linux_fstab_unescape fs_label + IFS=$'\0' + COMPREPLY+=("$fs_label") + IFS=$oldifs + fi + else + __linux_fstab_unescape fs_spec + __linux_fstab_unescape fs_file + IFS=$'\0' + [[ $fs_spec = */* ]] && COMPREPLY+=("$fs_spec") + [[ $fs_file = */* ]] && COMPREPLY+=("$fs_file") + IFS=$oldifs + fi + done + + _reply_compgen_array +} + _mount() { local cur sm host prev @@ -44,11 +112,11 @@ _mount() else # probably Linux if [ $prev = -L ]; then - COMPREPLY=( $( compgen -W '$(sed -ne "s/^[[:space:]]*LABEL=\([^[:space:]]*\).*/\1/p" /etc/fstab )' -- "$cur" ) ) + _linux_fstab -L < /etc/fstab elif [ $prev = -U ]; then COMPREPLY=( $( compgen -W '$(sed -ne "s/^[[:space:]]*UUID=\([^[:space:]]*\).*/\1/p" /etc/fstab )' -- "$cur" ) ) else - COMPREPLY=( $( compgen -W "$( awk '! /^[ \t]*#/ {if ($2 ~ /\//) print $2}' /etc/fstab )" -- "$cur" ) ) + _linux_fstab < /etc/fstab fi fi @@ -62,12 +130,18 @@ complete -F _mount -o default -o dirnames mount have umount && _umount() { - local cur IFS=$'\n' - COMPREPLY=() - cur=`_get_cword` - COMPREPLY=( $( compgen -W '$( mount | cut -d" " -f 3 )' -- "$cur" ) ) + local cur=`_get_cword` + + if [[ $(uname -s) = Linux && -r /proc/mounts ]]; then + # Linux /proc/mounts is properly quoted. This is important when + # unmounting usb devices with pretty names. + _linux_fstab < /proc/mounts + else + local IFS=$'\n' + COMPREPLY=( $( compgen -W '$( mount | cut -d" " -f 3 )' -- "$cur" ) ) + fi return 0 } && diff --git a/test/fixtures/mount/test-fstab b/test/fixtures/mount/test-fstab new file mode 100644 index 00000000..b2434173 --- /dev/null +++ b/test/fixtures/mount/test-fstab @@ -0,0 +1,24 @@ +proc /proc proc defaults 0 0 +none /debug debugfs defaults,noauto 0 0 + +# Simple obvious test. +/mnt/nice-test-path /dev/null auto ro,noauto 0 0 + +# Test octal escapes +# Contains ' ' and '-' +/mnt/nice\040test\055path /dev/null auto ro,noauto 0 0 +# Contains '$' and '-' +/mnt/nice\044test\055path /dev/null auto ro,noauto 0 0 +# Contains ' ' and '\\' +/mnt/nice\040test\134path /dev/null auto ro,noauto 0 0 +# Contains '\n' and '\ ' +/mnt/nice\012test\040path /dev/null auto ro,noauto 0 0 + +# Test apostrophe +/mnt/nice'test-path /dev/null auto ro,noauto 0 0 +/mnt/other'test\040path /dev/null auto ro,noauto 0 0 + +# Test some labels +LABEL=Ubuntu\040Karmic /mnt/ubuntu auto no,noauto 0 0 +LABEL=Fedora /mnt/fedora auto ro,noauto 0 0 +LABEL=Debian-it's\040awesome /mnt/debian auto ro,noauto 0 0 diff --git a/test/lib/completions/mount.exp b/test/lib/completions/mount.exp index 9e40803e..9e98cc6d 100644 --- a/test/lib/completions/mount.exp +++ b/test/lib/completions/mount.exp @@ -1,11 +1,38 @@ +# mount completion from fstab can't be tested directly because it +# (correctly) uses absolute paths. So we create a custom completion which +# reads from a file in our text fixture instead. +proc setup_dummy_mnt {} { + assert_bash_exec {unset COMPREPLY cur} + assert_bash_exec {unset -f _mnt} + + global TESTDIR + assert_bash_exec { \ + _mnt() { \ + local cur=$(_get_cword); \ + _linux_fstab $(_get_pword) < "$TESTDIR/fixtures/mount/test-fstab"; \ + }; \ + complete -F _mnt mnt \ + } +} + + +proc teardown_dummy_mnt {} { + assert_bash_exec {unset COMPREPLY cur} + assert_bash_exec {unset -f _mnt} + assert_bash_exec {complete -r mnt} +} + + proc setup {} { save_env -}; + setup_dummy_mnt +} proc teardown {} { + teardown_dummy_mnt assert_env_unmodified -}; +} setup @@ -30,4 +57,58 @@ assert_bash_exec {PATH="$OLDPATH"; unset -v OLDPATH} sync_after_int +set test "Testing internal __linux_fstab_unescape function for mount" +# One round of slashes is for bash. +assert_bash_exec {var=one\'two\\040three\\} +assert_bash_exec {__linux_fstab_unescape var} +set cmd {echo $var} +send "$cmd\r" +expect { + -ex "$cmd\r\none'two three\\" { pass $test } +# default { fail $test } +} +assert_bash_exec {unset var} + + +sync_after_int + + +# Begin testing through mnt (see setup_dummy_mnt). +assert_complete {/mnt/nice-test-path} {mnt /mnt/nice-test-p} +sync_after_int + +assert_complete {/mnt/nice\ test-path} {mnt /mnt/nice\ test-p} +sync_after_int + +assert_complete {/mnt/nice\$test-path} {mnt /mnt/nice\$test-p} +sync_after_int + +assert_complete {/mnt/nice\ test\\path} {mnt /mnt/nice\ test\\p} +sync_after_int + +assert_complete {{/mnt/nice\ test\\path} {/mnt/nice\ test-path}} \ + {mnt /mnt/nice\ } "" /@ 20 {/mnt/nice\ } +sync_after_int + +assert_complete {/mnt/nice\$test-path} {mnt /mnt/nice\$} +sync_after_int + +assert_complete {/mnt/nice\'test-path} {mnt /mnt/nice\'} +sync_after_int + +assert_complete {/mnt/other\'test\ path} {mnt /mnt/other} +sync_after_int + +assert_complete {Ubuntu\ Karmic} {mnt -L Ubu} +sync_after_int + +assert_complete {Debian-it\'s\ awesome} {mnt -L Deb} +sync_after_int + +# This does not work. Proper support for this requires smarter parsing of +# $COMP_LINE and it's not worth doing just for mount. +#assert_complete {$'/mnt/nice\ntest-path'} {mnt $'/mnt/nice\n} +#sync_after_int + + teardown |