6

In the Pyenv project, we've had a peculiar problem.

We are substituting python (and python*) with our Bash scripts ("shims") that select a Python executable to run at runtime.

Now, some users wish to use a special selection logic when a Python script is run as path/to/script.py. The problem is, this logic should NOT apply if the script is instead run as <python> path/to/script.py!

Is there a way to reliably distinguish these two cases?

I wasn't able to find anything: depending on the way command line arguments are formulated in the 2nd case, the exact same command line could be executed in both cases:
(the Bash script given is not a real shim, just a demonstration example to showcase what our logic sees and does)

$ cat python3 
#!/bin/bash
echo "'$0'"
for a in "$@"; do
  echo "'$a'"
done
# need to do the detection here
exec python3 "$@"

$ cat t.py 
#!/home/vmuser/python3
import sys
print(sys.argv)

$ $PWD/t.py
'/home/vmuser/python3' 
'/home/vmuser/t.py'
['/home/vmuser/t.py']

$ $PWD/python3 $PWD/t.py 
'/home/vmuser/python3'
'/home/vmuser/t.py'
['/home/vmuser/t.py']

Since shebang is a Linux kernel feature -- maybe it sets some indicator that this mechanism has been used?


We've considered requiring users to use a special shebang in their Python scripts that they wish to apply the special logic to, but that idea proved unpopular because it makes those scripts unportable.

5
  • 1
    Have a look at this one.
    – Quasímodo
    Jul 3, 2021 at 14:52
  • @Quasímodo the linked question requires a special shebang that's not usable outside of Pyenv. We had such an idea but it proved unpopular with users because it makes scripts unportable. Jul 3, 2021 at 15:08
  • Can you create a "launcher" script/binary (in python, compiled c, or whatever you choose) as an option? I.E., the launcher can be version agnostic in itself, and selects the appropriate python* interpreter to pass the rest of the script to. Doing this, you can also allow your end-users methods to pass additional information, such as in specially formatted comments in the first few lines, to give it any additional hints/directions.
    – C. M.
    Jul 3, 2021 at 16:26
  • 1
    You might be interested in python-exec. I have no idea how much actual overlap there is with your use case, but I suspect they had to solve some of the same problems as you are facing. Jul 4, 2021 at 2:29
  • @AustinHemmelgarn we've had that idea, too, and that's what we currently suggest as an alternative to the requested feature -- a plugin that allows to create a separate set of manually configured shims for select scripts. Jul 4, 2021 at 7:41

1 Answer 1

7

Since shebang is a Linux kernel feature -- maybe it sets some indicator that this mechanism has been used?

Yes, it does. Linux sets the AT_EXECFN auxiliar vector entry to the path of the original executable. In C, you can do it with char *at_execfn = (char*)getauxval(AT_EXECFN), followed by stat(at_execfn), etc.

Getting it from bash is tricky, though. You can try unpacking the /proc/self/auxv and then looking through /proc/self/mem. Good luck with that ;-)

5
  • Well, that does it... If I use a C program equivalent instead of the Bash script, at_execfn is /home/vmuser/t.py in the 1st case and /home/vmuser/python3 in the 2nd. But then the question arises how to do this in other OSes. We officially support MacOS as well, it's BSD-based. Jul 3, 2021 at 15:51
  • I'll check if MacOS has an equivalent to AT_EXECFN Jul 3, 2021 at 15:54
  • You could check if among these: stackoverflow.com/questions/1023306/… some wouldn't work like AT_EXECFN (rather than falling back to OP's initial problem)?
    – A.B
    Jul 3, 2021 at 16:21
  • @A.B no dice. Both _dyld_get_image_name and _NSGetExecutablePath give post-shebang name. Jul 3, 2021 at 18:08
  • Asked about MacOS at SO: stackoverflow.com/questions/68238888/… Jul 3, 2021 at 18:30

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .