Search code examples
c#linuxsshssh.net4gl

Command (.4gl) executed with SSH.NET SshClient.RunCommand fails with "No such file or directory"


I have a web service that uses SSH.NET to call a shell script on a Unix box.

If I run the script normally, it works fine, does its work correctly on the Informix DB.

Just some background:
I call a script that executes a .4gl (cant show this as its business knowledge).

The g4l is giving the following error back in a log, when I execute it with SSH.NET:

fglgo: error while loading shared libraries: libiffgisql.so: cannot open shared object file: No such file or directory
file_load ended: 2017-09-21 15:37:01

C# code to execute SSH.NET script

sshclients = new SshClient(p, 22, username, password);
sshclients.Connect();
sshclients.KeepAliveInterval = new TimeSpan(0, 0, 1);
sshclients.RunCommand("sh " + Script_dir);

I added the KeepAliveInterval, to see, if it helps.

My question is the error I am getting from Unix/4gl.
Why is this happening and who can I get the script to execute correctly?


Solution

  • The SshClient.RunCommand uses SSH "exec" channel internally. It, by default, (rightfully) does not allocate a pseudo terminal (PTY) for the session. As a consequence a different set of startup scripts is (might be) sourced. And/or different branches in the scripts are taken, based on absence/presence of the TERM environment variable. So the environment might differ from the interactive session, you use with your SSH client.

    So, in your case, the PATH is probably set differently; and consequently the shared object cannot be found.

    To verify that this is the root cause, disable the pseudo terminal allocation in your SSH client. For example in PuTTY, it's Connection > SSH > TTY > Don't allocate a pseudo terminal. Then, go to Connection > SSH > Remote command and enter your g4l command. Check Session > Close window on exit > Never and open the session. You should get the same "No such file or directory" error.


    Ways to fix this, in preference order:

    1. Fix the scripts not to rely on a specific environment.

    2. Fix your startup scripts to set the PATH the same for both interactive and non-interactive sessions.

    3. If the command itself relies on a specific environment setup and you cannot fix the startup scripts, you can change the environment in the command itself. Syntax for that depends on the remote system and/or the shell. In common *nix systems, this works:

       sshclients.RunCommand("PATH=\"$PATH;/path/to/g4l\" && sh ...");
      
    4. Another (not recommended) approach is to force the pseudo terminal allocation for the "exec" channel.

      Though SSH.NET does not support this. You would have to modify its code issue SendPseudoTerminalRequest request in .RunCommand implementation (I didn't test this).

      You can also try to use "shell" channel using .CreateShell method. For it, SSH.NET does support pseudo terminal allocation.

      Though, using the pseudo terminal to automate a command execution can bring you nasty side effects. See for example Is there a simple way to get rid of junk values that come when you SSH using Python's Paramiko library and fetch output from CLI of a remote machine?


    For a similar issues, see