Bug 2009547

Summary: which treats function contents as aliases when parsing ksh "typeset -f" output
Product: Red Hat Enterprise Linux 8 Reporter: Dave Weller-Fahy <redhat-bugzilla>
Component: whichAssignee: Than Ngo <than>
Status: CLOSED ERRATA QA Contact: Jakub Haruda <jharuda>
Severity: unspecified Docs Contact:
Priority: unspecified    
Version: CentOS StreamCC: bstinson, dareynol, efedin, jonathanneumann, jwboyer
Target Milestone: rcKeywords: Triaged
Target Release: 8.6   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard:
Fixed In Version: which-2.21-17.el8 Doc Type: No Doc Update
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2022-05-10 15:25:05 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:

Description Dave Weller-Fahy 2021-09-30 22:52:26 UTC
Description of problem: When using which alias [1] in ksh [2] that was
introduced in version 2.21-5 [3] does not handle the output of
typeset -f properly.

[1]: alias which='(alias; typeset -f) | /usr/bin/which --tty-only --read-alias --read-functions --show-tilde --show-dot'

[2]: rpm -qf /bin/ksh -> ksh-20120801-252.el8.x86_64

[3]: https://src.fedoraproject.org/rpms/which/c/7128ddbd689c34c1fd4f7790a91b9be243f2d304?branch=rawhide

Version-Release number of selected component (if applicable): 2.21-5+

How reproducible: Reproducible always

Steps to Reproduce:
1. Create a test function.

cat <<EOF > testfunc.ksh
testfunc1() {
  true >/dev/null
}
EOF

2. Source the test function in the current environment.

. ./testfunc1.ksh

3. Use the which alias to try to find the command true.

which true

Actual results: (comments are to delineate output)

#v+
  true >/dev/null
#v-

Expected results: (comments are to delineate output)

#v+
/bin/true
#v-

Additional info:

Removing the --read-alias parameter of the default alias allows the desired (in this case) answer, however that would also prevent the aliases from being included in the which results.

In addition, the failure of parsing within which seems to be based on the space between the function name and the parenthesis.

The function definitions listed below cause the expected results:

testfunc2 () {
  true >/dev/null
}

testfunc3 ()
{
  true >/dev/null
}

Note that ksh seems to reformat the function names and parenthesis to remove spaces between them. Entering testfunc2 into ksh, then using typeset -f, results in testfunc1. Entering testfunc3 into ksh, then using typeset -f, results in the function below, which causes the actual results (the error).

testfunc()
{
  true >/dev/null
}

Comment 1 Than Ngo 2021-10-01 08:24:53 UTC
this issue was already fixed in latest which. It should be included in next centos update.

Comment 2 Dave Weller-Fahy 2021-10-01 11:39:19 UTC
Ah, thank you - I missed the eval fix when going through the commits, because I was focused on finding where it was introduced.

Comment 3 Dave Weller-Fahy 2021-10-01 13:27:23 UTC
Unfortunately, I do not think this is fixed. On my system, using ksh-20120801-252.el8.x86_64 and which-2.21-12.el8.x86_64, I replaced /etc/profile.d/which2.sh with the file in 2.21-27 [1], and I still get an incorrect result.

[1]: https://src.fedoraproject.org/rpms/which/blob/996c9e58cca0efa7fb41ea3b3060c2a23c4f8841/f/which2.sh

#v+
$ echo $which_declare
typeset -f
$ typeset -f | grep -A 3 ^which
which()
{
(alias; eval ${which_declare}) | /usr/bin/which --tty-only --read-alias --read-functions --show-tilde --show-dot "$@"
}
$ cat testfunc1
testfunc1() {
  true >/dev/null #1
}
$ . ./testfunc1
$ typeset -f | grep -A 2 ^testfunc1
testfunc1() {
  true >/dev/null #1
}
$ eval typeset -f | grep -A 2 ^testfunc1
testfunc1() {
  true >/dev/null #1
}
$ which true
  true >/dev/null #1
$ unset -f testfunc1
#v-

Note that the output (on this system) of typeset -f and eval typeset -f is identical, and does not insert the space between the function name and parenthesis that seems to be required by which. Taking the alias out of the picture, the behavior is the same as it was before, with the following test cases.

#v+
$ cat testfunc2
testfunc2 () {
  true >/dev/null #2
}
$ cat testfunc3
testfunc3 ()
{
  true >/dev/null #3
}
$ cat testfunc4
testfunc4()
{
  true >/dev/null #4
}
$ cat testfunc
/usr/bin/which --tty-only --read-alias --read-functions --show-tilde --show-dot true < ./testfunc1
/usr/bin/which --tty-only --read-alias --read-functions --show-tilde --show-dot true < ./testfunc2
/usr/bin/which --tty-only --read-alias --read-functions --show-tilde --show-dot true < ./testfunc3
/usr/bin/which --tty-only --read-alias --read-functions --show-tilde --show-dot true < ./testfunc4

/usr/bin/which --tty-only --read-functions --show-tilde --show-dot true < ./testfunc1
/usr/bin/which --tty-only --read-functions --show-tilde --show-dot true < ./testfunc2
/usr/bin/which --tty-only --read-functions --show-tilde --show-dot true < ./testfunc3
/usr/bin/which --tty-only --read-functions --show-tilde --show-dot true < ./testfunc4
$ ksh ./testfunc
  true >/dev/null #1
/bin/true
/bin/true
  true >/dev/null #4
/bin/true
/bin/true
/bin/true
/bin/true
#v-

Please let me know if you need more information, or want me to run any commands or tests on my end.

Comment 4 Dave Weller-Fahy 2021-10-06 23:11:43 UTC
I noticed it stayed closed when I submitted the most recent information. This particular behavior is not fixed by the changes to the which2.sh script, so I've changed it back to NEW. Please let me know if I should have done this another way.

Comment 6 Than Ngo 2021-10-10 12:22:06 UTC
This issue is fixed in which-2.21-28.fc36. Could you please download and test it?

  https://koji.fedoraproject.org/koji/taskinfo?taskID=77010249

Thanks

Comment 7 Dave Weller-Fahy 2021-10-23 03:36:55 UTC
Hi Than - sorry for the delayed reply.

Neither 2.21-28 nor 2.21-29 fix the issue. I'm using /bin/ksh from the packages ksh-20120801-252.el8.x86_64 and ksh-20120801-142.el7.x86_64.

The command 'typeset -fS' does not display any functions on my system, and I believe that is because '-S' does not change the display of the functions. It just changes the type of a function (to static). Per the man page: 'The -S can be used with discipline functions defined in a type to indicate that the function is static.' In addition, the version of mksh I found in RHEL 8.2 and 7.8 does not have a '-S' option.

Based on a quick read of the which.c file, it looks like which does not support ksh-style function output. Given that, I think we can patch and submit that patch upstream [1], disable the --read-functions option in korn shells, or do some munging of the 'typeset -f' output. The latter could be fragile, but might be a reasonable path forward.

[1]: https://carlowood.github.io/which/index.html

The way I would implement it is to execute the following, capture the output, and feed it into which as the function output.

typeset -f |
    sed -r -e 's/([A-Za-z_][A-Za-z0-9_]+)\(\) *(\{?)/\1 () \2/' |
    sed -r -e 's/function ([A-Za-z_][A-Za-z0-9_]+) *(\{?)/\1 () \2/'

That follows the rules of what qualifies as the name of a function, uses the two patterns documented in the ksh man page, and reformats them so that which understands the functions. There is some weirdness with nested functions that we could discuss, but which identifies the proper function in that case, and does *not* identify the nested function as valid in its context (which is the correct thing to do).

Please let me know if you need any more information from me.

Comment 8 Than Ngo 2021-10-26 15:41:08 UTC
which upstream project is dead, there is no development since 2015/03/20. For this reason i think the best option is to disable --read-functions option in korn shells.

Comment 9 Dave Weller-Fahy 2021-10-26 15:53:54 UTC
Concur - I didn't realize it had been that long, and the behavior you describe is just returning to the way the package worked previously (not accounting for functions). Thanks!

Comment 17 Than Ngo 2021-12-08 15:27:51 UTC
*** Bug 2030366 has been marked as a duplicate of this bug. ***

Comment 20 Than Ngo 2022-03-29 07:42:04 UTC
*** Bug 2063018 has been marked as a duplicate of this bug. ***

Comment 22 errata-xmlrpc 2022-05-10 15:25:05 UTC
Since the problem described in this bug report should be
resolved in a recent advisory, it has been closed with a
resolution of ERRATA.

For information on the advisory (which bug fix and enhancement update), and where to find the updated
files, follow the link below.

If the solution does not work for you, open a new bug report.

https://access.redhat.com/errata/RHBA-2022:2067