-1

Is it possible to use a "more complex" shell than just a single command shell? We have written a python shell that is a command loop, and it works fine in /etc/passwd like this:

user:x:1000:1000::/home/user:/usr/bin/ourshell.py

Of course the Python file has the shebang line for /usr/bin/python in it. However, we'd like to compile the Python shell into a .pyc file to save a bit of time on execution in login. So, after compiling, I've been trying to "quote" the shell line in /etc/passwd as "python ourshell.pyc", and I even tried making the shell a bash script which simply executes that same command (with the initial arguments).

Of course none of this has worked. When we SSH in, there is always some kind of error. Is there any special trick to what I am trying to do?

Nathan Smith
  • 643
  • 1
  • 11
  • 21
Kevin Hirst
  • 846
  • 7
  • 16
  • 3
    "there is always some kind of error". How about show the errors you have. – MrJLP Sep 01 '17 at 19:24
  • 2
    Whatever delay you may be experiencing with `ourshell.py` starting probably as far more to do with the Python interpreter itself than the time it takes to compile `ourshell.py`. – chepner Sep 01 '17 at 19:24
  • I highly recommend against [using `/usr/bin/python`](https://stackoverflow.com/questions/2429511/why-do-people-write-usr-bin-env-python-on-the-first-line-of-a-python-script) – Nathan Smith Sep 01 '17 at 19:26
  • 1
    @NathanSmith The correct thing to do is let whoever is *installing* the script choose the shebang, not the person writing the script. The installer knows where the correct version of Python is. `distutils` manages this by replacing `#!python` with the correct path at install time. – chepner Sep 01 '17 at 19:33
  • It's **extremely** unlikely that loading this module as a .pyc file will save any appreciable amount of time unless it's incredibly complex to parse (in which case you should refactor it for unrelated reasons). Usually Python-interpreter startup time is driven by the time to load library modules. – Charles Duffy Sep 01 '17 at 19:52
  • The strict reasoning here is that we are using the SSH "exec" protocol, which executes the shell with a single command argument -c. I did a sample test run of 2000 commands using both "ourshell.py -c ..". and "python ourshell.pyc -c ..." and the average time went from 6.5 seconds to 5.5 seconds. And this means a lot since we're scripting a lot of devices and need the time savings. – Kevin Hirst Sep 01 '17 at 20:02
  • That falls into the "ought to be refactored" category, then. If you were using setuptools to build the executable wrapper for your script, for instance (see the `console_scripts` entry in `setup.py`), then the generated wrapper would be extremely short and simple to parse, and would just be loading a (pre-parsed to .pyc, if you installed it correctly) library and executing same. – Charles Duffy Sep 01 '17 at 20:15

3 Answers3

1

CPython's .pyc files are not text, and do not allow use of a shebang line. The traditional method is to have your called script be tiny; it would simply import a module with the rest of the program, which can then be precompiled. For instance, here is the main script of xonsh:

#!/usr/bin/env python3 -u
from xonsh.main import main
main()

This script takes negligible time to compile. It is also possible to run installed modules using -m, but that takes module names, not filenames, so is not suitable for a shebang script.

Yann Vernier
  • 13,812
  • 2
  • 24
  • 25
  • CPython can run bytecode just as it runs source code, no command line option is needed – MrJLP Sep 01 '17 at 19:37
  • I was mistaken. It does carry a potential downside in that the precompiled format is version specific, though, and isn't shebang compatible... one could use binfmt_misc on Linux to make these executable then. I suspect users wouldn't appreciate being suddenly unable to login when Python is upgraded. – Yann Vernier Sep 01 '17 at 19:41
0

I suggest to code a small C wrapper program running your python shell.

(notice that execve(2) forbids nested shebang interpreters; I don't know if that applies for your case)

Look into your log files, probably /var/log/messages and /var/log/auth.log

You may also need to explicitly add (the compiled C executable for the wrapper) to /etc/shells; see shells(5)

Look also into scsh.

Your sshd daemon is probably using Linux Plugin Authentification Modules. So read more about PAM.

Basile Starynkevitch
  • 1
  • 16
  • 251
  • 479
  • It's Dropbear for ARM From the log: Sep 1 19:41:48 InovaOnAlert-d28 authpriv.info dropbear[24120]: Exit (user): Child failed Sep 1 19:41:48 InovaOnAlert-d28 authpriv.err dropbear[24120]: chown /dev/pts/0 0 0 failed: Operation not permitted Sep 1 19:41:48 InovaOnAlert-d28 authpriv.info dropbear[24119]: Exit (user): Disconnect received – Kevin Hirst Sep 01 '17 at 19:45
0

Create a file /usr/bin/shell_wrapper that contains this one line:

#!/usr/bin/python /usr/bin/ourshell.pyc

The compiled bytecode ourshell.pyc has to live in /usr/bin, or else change the path accordingly. The python path should go to the same version that compiled the bytecode.

Then make sure to have your /etc/passwd use /usr/bin/shell_wrapper for the shell executable:

user:x:1000:1000::/home/user:/usr/bin/shell_wrapper
MrJLP
  • 930
  • 6
  • 14