[Bash-completion-devel] [bash-completion-Bugs][311410] ULP 219971: Doesn't handle escaped spaces in /etc/fstab well
bash-completion-bugs at alioth.debian.org
bash-completion-bugs at alioth.debian.org
Mon Feb 15 13:43:51 UTC 2010
Bugs item #311410, was changed at 2009-01-30 11:25 by Leonard Crestez
You can respond by visiting:
https://alioth.debian.org/tracker/?func=detail&atid=413095&aid=311410&group_id=100114
>Status: Closed
Priority: 2
Submitted By: David Paleino (hanska-guest)
Assigned to: Nobody (None)
Summary: ULP 219971: Doesn't handle escaped spaces in /etc/fstab well
Distribution: None
Originally reported in: Ubuntu Launchpad
Milestone: None
Status: None
Original bug number: 219971
Initial Comment:
Binary package hint: bash-completion
Because of I can't use "/some path" or /some\ path in fstab, I write some\040path as mount point.
I write "mount /some" in bash and press Tab, I see "mount /some\\040path" instead of "mount /some\ path"
----------------------------------------------------------------------
>Comment By: Leonard Crestez (cdleonard-guest)
Date: 2010-02-15 15:43
Message:
Fixed in the mount-fix which was just merged. The fix includes tests and also applies to umount and mounting by label.
----------------------------------------------------------------------
Comment By: Leonard Crestez (cdleonard-guest)
Date: 2010-01-21 12:46
Message:
Linux fstab can contain octal (and only octal) escapes. Interpreting them is
easy; the same style of escaping is supported by bash $'escaped strings'. Bash
supports more that just octal but those shouldn't be in fstab anyway.
Actually completing on mount points and devices with special characters is
hard. The -o filenames option can't be used because "filename specific
processing" does too much here. It will split on / and only print the last
component of the pathname as a complete option. This means that 'mount /<TAB>'
will show devices like sda1 and sda2 as variants. This is bad, even though the
actual completion works correctly.
The only way I could eventually get this to work is by making my own function
to complete over an array with strings containing strange characters. I tested
and it works with spaces, dolar-signs and newlines. It's some very nasty ugly
fragile code. Somehow I feel I must have missed something obvious; this should
have been easier.
Anyway; this function doesn't belong in mount completion. It would make sense
to move it to bash_completion as a generic utility. If you want I can
submit a revised version which does that and adds unit tests as well.
I tested by editting my /etc/fstab. Automatic testing for mount would require
either adding a special $FSTAB_LOCATION (ugly) or a chroot (hard).
There are various unrelated things wrong with this completion. For example:
parsing mount(8) output is fragile. On linux you can read /proc/mounts
instead; that file is in the fstab(5) format with octal escapes. I tried to
avoid unrelated changes.
Comments welcome. I wanted to send a small patch but it seems I couldn't solve
it with a small patch.
diff --git a/contrib/mount b/contrib/mount
index 0474df0..622ff88 100644
--- a/contrib/mount
+++ b/contrib/mount
@@ -1,12 +1,38 @@
-# mount(8) completion. This will pull a list of possible mounts out of
-# /etc/{,v}fstab, unless the word being completed contains a ':', which
-# would indicate the specification of an NFS server. In that case, we
-# query the server for a list of all available exports and complete on
-# that instead.
-#
+# mount(8) completion.
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 wlist
+ for i in ${!COMPREPLY[*]}; do
+ local q=`printf %q "${COMPREPLY[$i]}"`
+ wlist+=$(quote "$q")$'\n'
+ done
+
+ # We also have to add another round of escaping to $cur.
+ local ecur="$cur"
+ ecur="${ecur//\\/\\\\}"
+ ecur="${ecur/#$\'/\$\'}"
+
+ # Actually generate completions.
+ IFS=$'\n' eval 'COMPREPLY=(`compgen -W "$wlist" -- "${ecur}"`)'
+
+ # Strip starting $' in reply if present in cur.
+ # This is necesarry because readline interprets everything after ' as a
+ # separate word for completion.
+ if [[ $cur == $\'* ]]; then
+ COMPREPLY=( "${COMPREPLY[@]/#$\'}" )
+ fi
+}
+
_mount()
{
local cur i sm host prev
@@ -16,12 +42,15 @@ _mount()
[[ "$cur" == \\ ]] && cur="/"
prev=${COMP_WORDS[COMP_CWORD-1]}
+ # Look for the NFS showmount program.
for i in {,/usr}/{,s}bin/showmount; do [ -x $i ] && sm=$i && break; done
if [[ -n "$sm" && "$cur" == *:* ]]; then
+ # Complete NFS exports
COMPREPLY=( $( compgen -W "$( $sm -e ${cur%%:*} | \
awk 'NR>1 {print $1}' )" -- "$cur" ) )
elif [[ "$cur" == //* ]]; then
+ # Complete samba shares when starting with multiple slashes.
host=${cur#//}
host=${host%%/*}
if [ -n "$host" ]; then
@@ -39,18 +68,25 @@ _mount()
COMPREPLY=( $( compgen -W "$( mount | awk '! /^[ \t]*#/ {if ($3 ~ /\//) print $3}' )" -- "$cur" ) )
else
# probably Linux
- if [ $prev = -L ]; then
+ if [[ $prev = -L ]]; then
COMPREPLY=( $( compgen -W '$(sed -ne "s/^[[:space:]]*LABEL=\([^[:space:]]*\).*/\1/p" /etc/fstab )' -- "$cur" ) )
- elif [ $prev = -U ]; then
+ 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" ) )
+ COMPREPLY=()
+ while read -r fs_spec fs_file fs_other; do
+ if [[ $fs_spec = [#]* ]]; then continue; fi
+ [[ $fs_spec = */* ]] && { IFS=$'\0' eval "COMPRELPY+=( $'$fs_spec' )"; }
+ [[ $fs_file = */* ]] && { IFS=$'\0' eval "COMPREPLY+=( $'$fs_file' )"; }
+ done < /etc/fstab
+
+ _reply_compgen_array
fi
fi
return 0
} &&
-complete -F _mount -o default -o dirnames mount
+complete -F _mount -o dirnames mount
# umount(8) completion. This relies on the mount point being the third
# space-delimited field in the output of mount(8)
----------------------------------------------------------------------
Comment By: David Paleino (hanska-guest)
Date: 2009-01-30 11:25
Message:
DBTS 511149:
From: James Westby <james.westby at canonical.com>
To: Debian Bug Tracking System <submit at bugs.debian.org>
Subject: Doesn't handle escaped spaces in /etc/fstab well
Date: Wed, 07 Jan 2009 19:35:16 +0000
Package: bash-completion
Version: 20080705
Severity: minor
Hi,
In https://bugs.launchpad.net/ubuntu/+source/bash-completion/+bug/219971
Danil Ilinykh reported that the handling of escaped spaces in /etc/fstab
is not ideal.
"Because of I can't use "/some path" or /some\ path in fstab, I write
some\040path as mount point. I write "mount /some" in bash and press
Tab, I see "mount /some\\040path" instead of "mount /some\ path""
I can verify this behaviour on sid.
Thanks,
James
----------------------------------------------------------------------
You can respond by visiting:
https://alioth.debian.org/tracker/?func=detail&atid=413095&aid=311410&group_id=100114
More information about the Bash-completion-devel
mailing list