On 09/24/2010 02:22 PM, Stefan Berger wrote:
I just tried the TCK test without and with double-escaping in libvirtd
and double-escaping does seem to be necessary otherwise `ls` and $(ls)
do get executed and their results end up in the comment. The spaces
are preserved, though, so I can revert the change to IFS.
Hmm.
"res=`eval \"$cmd\"" CMD_SEPARATOR
+ virBufferVSprintf(buf,
+ " -m comment --comment \\\"%s\\\"",
+ cmt);
Thinking about it more:
Let's see why double-escaping helped you, by setting up a user comment
with two spaces and a $. You ultimately want to call:
iptables -m comment --comment 'user $comment'
but you used a "" style, resulting in:
iptables -m comment --comment "user \$comment"
Then, you are capturing that command in a shell variable $cmd (to avoid
repetition when displaying a failed command) and the output in $res. So
you need one level of escaping for assigning to cmd within "" context:
cmd="iptables -m comment --comment \"user \\\$comment\""
res=`$cmd`
Oops, that failed, because it splits $cmd at IFS boundaries, which
breaks up the user comment because it looks roughly like
res=`'iptables' '-m' 'comment' '--comment' '"user' '\$comment"'`
But quoting $cmd isn't right either, because then you try to execute a
single command with no arguments:
res=`"$cmd"`
res=`'iptables -m comment --comment "user \$comment"'`
So you _do_ need eval to control where the word boundaries are, which
means you will be removing a level of quoting from the contents of $cmd,
and you also need quoting when assigning to cmd, so I now see why double
escaping is needed. Continuing on with your original example, your
underquoted version with IFS cleared to avoid field splitting of $cmd
looks like:
IFS=
cmd="iptables -m comment --comment \"user \\\$comment\""
res=`eval $cmd`
res=`eval 'iptables -m comment --comment "user \$comment"'`
res=`iptables -m comment --comment "user $comment"`
oops - here, `` turned \$ into $ before the eval got run, which means
eval will expand the (empty variable) $comment. Even with two levels of
quoting, you risk problems when mixing "" and ``.
My suggestion is to assign cmd using '' rather than "" (fewer things to
quote), as well as moving the eval outside of the `` (so it becomes
obvious which \ are interpreted by eval rather than by ``:
cmd='iptables -m comment --comment '\''user $comment'\''
eval res=\`"$cmd"\`
res=`iptables -m comment --comment 'user $comment'`
And the nice part of that is the implementation:
virBufferVSprintf(buf, " -m comment --comment '%s'",
escapeSingleQuotes(user_comment));
virBufferVSprintf(cmd, "cmd='%s'\nres=\\`\"$cmd\"\\`",
escapeSingleQuotes(buf));
still results in the needed double quoting (one for assignment to cmd,
and one to be stripped by eval), but via two passes of a single function
that only has to escape all instances of ', rather than a function that
has to add escaping for four different bytes and pay attention to how
many escape levels must be added.
Ouch. That's probably 4x slower than the glibc version. I'd much
rather see:
#undef strchr
Yes, that does the trick. Thanks.
or
(strchr)(a, b)
On further thought, gnulib might be doing:
#define strchr rpl_strchr
on platforms where strchr is broken, so using #undef strchr is too
risky. So I'd recommend sticking with (strchr)(a, b), which still works
if gnulib has to replace a broken strchr.
(It's surprising how easy it is to have bugs in such a low-level
function - until just this month, glibc 2.12 on Alpha hardware had a bug
in memchr that gnulib has to work around).
--
Eric Blake eblake@xxxxxxxxxx +1-801-349-2682
Libvirt virtualization library http://libvirt.org
--
libvir-list mailing list
libvir-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/libvir-list