1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-03-09 15:50:02 +00:00

Fix multiple bugs when using 'alias -p' to print aliases (#398)

This commit was originally intended to fix just one bug with shcomp's
handling of 'alias -p', but while fixing that I found a large number
of related issues in the alias command's -p, -t and -x options. The
current patch provides bugfixes for all of the bugs listed below:

1) Listing aliases in a script with 'alias -p' or 'alias' broke
   shcomp's bytecode output:
   https://github.com/ksh93/ksh/issues/87#issuecomment-813819122

2) Listing individual aliases with the -p option doesn't work:
      $ alias foo=bar bar=foo
      $ alias foo
      foo=bar
      $ alias -p foo  # No output

3) Listing specific tracked aliases with -pt does not display them
   in a reusable format, but rather adds another tracked alias:
      $ hash -r cat vi
      $ alias -pt vi  # No output
      $ alias -pt rm
      $ alias -t
      cat=/usr/bin/cat
      rm=/usr/bin/rm
      vi=/usr/bin/vi

4) Listing all tracked aliases with -pt does not output them in a
   reusable format (the resulting command printed only creates a
   normal alias, which is different from a tracked alias):
      $ hash -r cat
      $ alias -pt
      alias cat=/usr/bin/cat  # Expected 'alias -t cat'

5) Listing a non-existent alias with -p doesn't cause an error:
      $ unalias -a
      $ alias -p notanalias  # No output
      $ echo $?
      0
      $ alias notanalias
      notanalias: alias not found
      $ echo $?
      1
      $ hash -r
      $ alias -pt notacommand  # No output
      $ echo $?
      0

6) Attempting to list 256 non-existent aliases results in exit
   status zero:
      $ unalias -a
      $ alias $(awk -v ORS= 'BEGIN { for(i=0;i<256;i++) print "x "; }')
      x: alias not found
      --cut error message--
      $ echo $?
      0

Changes:

- typeset.c: Avoid printing anything while shcomp is compiling a
  script. This is needed because the alias command is run by shcomp
  to prevent parsing issues.

- b_alias(): To avoid adding tracked aliases with -pt, set
  tdata.aflag to '+' so that setall() and other related functions
  only list tracked aliases.

- b_alias(): Set tdata.pflag to 1 so that setall() and other
  functions recognize -p was passed.

- print_value(): Add support for listing specific aliases with
  'alias -p'.

- setall(): To avoid any issues with zombie tracked aliases (see also
  the regression tests) ignore tracked alias nodes marked with the
  NV_NOALIAS attribute. This bit is set for tracked alias nodes by
  the nv_rehash() function.

- setall(): For backward compatibility, continue incrementing the
  exit status for each invalid alias and tracked alias passed. This
  was already how alias behaved when listing aliases without -p, so
  using -p shouldn't cause a change in behavior:
      $ unalias -a
      $ alias foo bar
      foo: alias not found
      bar: alias not found
      $ echo $?
      2
  To fix bug 6, the exit status is set to one if an enforced 8-bit
  exit status would be zero.

- print_namval(): Set the prefix to 'alias -t' so that listing
  tracked aliases with 'alias -pt' works correctly.

- data/msg.c and include/name.h: Add an error message for when
  'alias -pt' doesn't find a tracked alias.

- tests/alias.sh: Add a ton of regression tests for the bugs fixed in
  this commit.
This commit is contained in:
Johnothan King 2021-12-26 16:25:05 -08:00 committed by Martijn Dekker
parent feeb62d15f
commit f7213f03a2
8 changed files with 245 additions and 10 deletions

View file

@ -104,5 +104,176 @@ unalias foo && err_exit 'unalias should return non-zero when a previously set al
err=$(set +x; { "$SHELL" -i -c 'unalias history; unalias r'; } 2>&1) && [[ -z $err ]] \
|| err_exit "the 'history' and 'r' aliases can't be removed (got $(printf %q "$err"))"
# ======
# Listing aliases in a script shouldn't break shcomp bytecode
exp="alias foo='bar('
alias four=4
alias three=3
alias two=2
foo='bar('
foo='bar('
four=4
three=3
two=2
foo='bar('
four=4
three=3
two=2
noalias: alias not found
ls=$(whence -p ls)
alias -t ls"
alias_script=$tmp/alias_script.sh
cat > "$alias_script" << EOF
unalias -a
alias foo='bar('
alias two=2
alias three=3
alias four=4
alias -p
alias foo
alias -x
alias
alias noalias
alias -t ls
alias -t
alias -pt
EOF
got=$(set +x; redirect 2>&1; $SHELL <($SHCOMP "$alias_script"))
[[ $exp == $got ]] || err_exit "Listing aliases corrupts shcomp bytecode" \
"(expected $(printf %q "$exp"), got $(printf %q "$got"))"
# Specifying an alias with 'alias -p' should print that alias in a reusable form
exp='alias foo=BAR'
got=$(
alias foo=BAR bar=FOO
alias -p foo
)
[[ $exp == $got ]] || err_exit "Specifying an alias with 'alias -p' doesn't work" \
"(expected $(printf %q "$exp"), got $(printf %q "$got"))"
got=$(
hash -r cat
alias -tx
alias -ptx
alias -ptx cat
alias -ptx nosuchcommand
)
[[ -z $got ]] || err_exit "The -x option should prevent output when combined with -t" \
"(got $(printf %q "$got"))"
# Listing members of the hash table with 'alias -pt' should work
exp='alias -t cat
vi: tracked alias not found
alias -t cat
alias -t chmod'
got=$(
set +x
redirect 2>&1
hash -r cat chmod
alias -pt cat vi # vi shouldn't be added to the hash table
alias -pt
)
[[ $exp == $got ]] || err_exit "Listing members of the hash table with 'alias -pt' doesn't work" \
"(expected $(printf %q "$exp"), got $(printf %q "$got"))"
# Attempting to list a non-existent alias or tracked alias should fail
# with an error message. Note that the exit status should match the
# number of aliases passed that don't exist.
exp='foo: alias not found
bar: alias not found
nosuchalias: alias not found'
got=$(
set +x
redirect 2>&1
unalias -a
alias foo bar nosuchalias
)
ret=$?
[[ $exp == $got ]] || err_exit "Listing non-existent aliases with 'alias' should fail with an error message" \
"(expected $(printf %q "$exp"), got $(printf %q "$got"))"
((ret == 3)) || err_exit "Listing non-existent aliases with 'alias' has wrong exit status" \
"(expected 3, got $ret)"
# Same as above, but tests alias -p with a different number
# of non-existent aliases.
exp='foo: alias not found
bar: alias not found
nosuchalias: alias not found
stillnoalias: alias not found'
got=$(
set +x
redirect 2>&1
unalias -a
alias -p foo bar nosuchalias stillnoalias
)
ret=$?
[[ $exp == $got ]] || err_exit "Listing non-existent aliases with 'alias -p' should fail with an error message" \
"(expected $(printf %q "$exp"), got $(printf %q "$got"))"
((ret == 4)) || err_exit "Listing non-existent aliases with 'alias -p' has wrong exit status" \
"(expected 4, got $ret)"
# Tracked aliases next.
exp='rm: tracked alias not found
ls: tracked alias not found'
got=$(
set +x
redirect 2>&1
hash -r
alias -pt rm ls
)
ret=$?
[[ $exp == $got ]] || err_exit "Listing non-existent tracked aliases with 'alias -pt' should fail with an error message" \
"(expected $(printf %q "$exp"), got $(printf %q "$got"))"
((ret == 2)) || err_exit "Listing non-existent tracked aliases with 'alias -pt' has wrong exit status" \
"(expected 2, got $ret)"
# Detect zombie aliases with 'alias'.
exp='vi: alias not found
chmod: alias not found'
got=$($SHELL -c '
hash vi chmod
hash -r
alias vi chmod
' 2>&1)
ret=$?
[[ $exp == $got ]] || err_exit "Listing removed tracked aliases with 'alias' should fail with an error message" \
"(expected $(printf %q "$exp"), got $(printf %q "$got"))"
((ret == 2)) || err_exit "Listing removed tracked aliases with 'alias' has wrong exit status" \
"(expected 2, got $ret)"
# Detect zombie aliases with 'alias -p'.
exp='vi: alias not found
chmod: alias not found'
got=$($SHELL -c '
hash vi chmod
hash -r
alias -p vi chmod
' 2>&1)
ret=$?
[[ $exp == $got ]] || err_exit "Listing removed tracked aliases with 'alias -p' should fail with an error message" \
"(expected $(printf %q "$exp"), got $(printf %q "$got"))"
((ret == 2)) || err_exit "Listing removed tracked aliases with 'alias -p' has wrong exit status" \
"(expected 2, got $ret)"
# Detect zombie tracked aliases.
exp='vi: tracked alias not found
chmod: tracked alias not found'
got=$($SHELL -c '
hash vi chmod
hash -r
alias -pt vi chmod
' 2>&1)
ret=$?
[[ $exp == $got ]] || err_exit "Listing removed tracked aliases with 'alias -pt' should fail with an error message" \
"(expected $(printf %q "$exp"), got $(printf %q "$got"))"
((ret == 2)) || err_exit "Listing removed tracked aliases with 'alias -pt' has wrong exit status" \
"(expected 2, got $ret)"
# The exit status on error must be >0, including when handling
# 256 non-existent aliases.
(unalias -a; alias $(integer -s i; for((i=0;i<256;i++)) do print -n "x "; done) 2> /dev/null)
got=$?
((got > 0)) || err_exit "Exit status is zero when alias is passed 256 non-existent aliases"
# ======
exit $((Errors<125?Errors:125))