Merge branch 'mount-fix'
Fix mount handling of escapes (Alioth: #311410, Launchpad: #219971) Conflicts: CHANGES
This commit is contained in:
commit
f294219990
1
CHANGES
1
CHANGES
@ -71,6 +71,7 @@ bash-completion (2.x)
|
|||||||
* Fix completion of usernames (Alioth: #311396, Debian: #511788).
|
* Fix completion of usernames (Alioth: #311396, Debian: #511788).
|
||||||
* Fix chown test crashing on systems with no root group (Alioth: #312306).
|
* Fix chown test crashing on systems with no root group (Alioth: #312306).
|
||||||
* Fixed tests when BASH_COMPLETION or TESTDIR contain spaces.
|
* Fixed tests when BASH_COMPLETION or TESTDIR contain spaces.
|
||||||
|
* Fix mount handling of escapes (Alioth: #311410, Launchpad: #219971).
|
||||||
|
|
||||||
[ Raphaël Droz ]
|
[ Raphaël Droz ]
|
||||||
* Add xsltproc completion (Alioth: #311843).
|
* Add xsltproc completion (Alioth: #311843).
|
||||||
|
@ -7,6 +7,74 @@
|
|||||||
have mount &&
|
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()
|
_mount()
|
||||||
{
|
{
|
||||||
local cur sm host prev
|
local cur sm host prev
|
||||||
@ -44,11 +112,11 @@ _mount()
|
|||||||
else
|
else
|
||||||
# probably Linux
|
# probably Linux
|
||||||
if [ $prev = -L ]; then
|
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
|
elif [ $prev = -U ]; then
|
||||||
COMPREPLY=( $( compgen -W '$(sed -ne "s/^[[:space:]]*UUID=\([^[:space:]]*\).*/\1/p" /etc/fstab )' -- "$cur" ) )
|
COMPREPLY=( $( compgen -W '$(sed -ne "s/^[[:space:]]*UUID=\([^[:space:]]*\).*/\1/p" /etc/fstab )' -- "$cur" ) )
|
||||||
else
|
else
|
||||||
COMPREPLY=( $( compgen -W "$( awk '! /^[ \t]*#/ {if ($2 ~ /\//) print $2}' /etc/fstab )" -- "$cur" ) )
|
_linux_fstab < /etc/fstab
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -62,12 +130,18 @@ complete -F _mount -o default -o dirnames mount
|
|||||||
have umount &&
|
have umount &&
|
||||||
_umount()
|
_umount()
|
||||||
{
|
{
|
||||||
local cur IFS=$'\n'
|
|
||||||
|
|
||||||
COMPREPLY=()
|
COMPREPLY=()
|
||||||
cur=`_get_cword`
|
|
||||||
|
|
||||||
|
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" ) )
|
COMPREPLY=( $( compgen -W '$( mount | cut -d" " -f 3 )' -- "$cur" ) )
|
||||||
|
fi
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
} &&
|
} &&
|
||||||
|
24
test/fixtures/mount/test-fstab
vendored
Normal file
24
test/fixtures/mount/test-fstab
vendored
Normal file
@ -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
|
@ -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 {} {
|
proc setup {} {
|
||||||
save_env
|
save_env
|
||||||
};
|
setup_dummy_mnt
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
proc teardown {} {
|
proc teardown {} {
|
||||||
|
teardown_dummy_mnt
|
||||||
assert_env_unmodified
|
assert_env_unmodified
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
setup
|
setup
|
||||||
@ -30,4 +57,58 @@ assert_bash_exec {PATH="$OLDPATH"; unset -v OLDPATH}
|
|||||||
sync_after_int
|
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
|
teardown
|
||||||
|
Loading…
x
Reference in New Issue
Block a user