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

6

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.