Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Opening file via commandline on remote? #267

Closed
spanishpear opened this issue Jun 24, 2021 · 16 comments
Closed

Opening file via commandline on remote? #267

spanishpear opened this issue Jun 24, 2021 · 16 comments
Labels
enhancement New feature or request

Comments

@spanishpear
Copy link

Hi!

I was wondering if there's any way to open a mounted file on the commandline from my ssh-terminal (as opened by the extension)?

Thanks!

@SchoofsKelvin
Copy link
Owner

It'll take a little bit to implement, but I think this can be done when #253 is (partially) implemented/released.

Basically bind to e.g. /tmp/vscode-sshfs-<random-UUID-or-timestamp>.sock which is remotely forwarded by the extension and listens for commands. A bash alias (or even an overridden $EDITOR variable) could then be added to perform echo "open <filepath>\n" > /tmp/.... Haven't tested it yet, but I imagine this would be a relatively simple way of adding support for this.

@SchoofsKelvin SchoofsKelvin added the enhancement New feature or request label Jun 26, 2021
@jcattley
Copy link

The only caveat I'd add:

We're trying to migrate our users to SSH-FS away from remote-ssh, because we have thousands of users connecting to our servers, and the .vscode-server backend that remote-ssh uses is a massive CPU/RAM/pid/disk hog - trivial for single-user boxes, but a major problem for significantly-multi-user environments. (it's also hilariously insecure by default, and people can end up running other users' shells accidentally unless they drill down into the config to use sockets instead of TCP...)

Killing stuck or leftover backend processes by the hundreds, and fielding multiple tickets daily to clear out corrupted or quota-eating .vscode-server directories is also a significant chunk of our daily workflow that we really want to get away from, and if we end up going back there, I may possibly cry.

If you do implement a backend process, I beg you to focus on keeping it as lightweight and stateless as possible. I will owe you one, seriously.

@SchoofsKelvin
Copy link
Owner

If you do implement a backend process, I beg you to focus on keeping it as lightweight and stateless as possible. I will owe you one, seriously.

I wasn't really thinking about a backend process anyway, as this would require the host to have NodeJS to run the backend code. That, or me having to write and provide (built) executables for every OS, which I'm even less a fan of. My idea was just to have a simple socket (a UNIX one, to prevent having to deal with reserved ports and such) which is either port forwarded through SSH, or optionally running a background SSH terminal that creates and listens to this socket, although the latter is unlikely.

@SchoofsKelvin
Copy link
Owner

SchoofsKelvin commented Jun 29, 2021

Made some progress, although actually injecting the code alias/function in the shell is tricky. And actually creating a code program in some .../bin directory seems a bit icky.

Currently I'm overwriting the PROMPT_COMMAND environment variable (for Bash) and the ENV environment variable (for sh) to have them load a temporary file (including in subshells) that adds the alias. Not the cleanest, and definitely not the most reliable/robust, let alone whether it supports other shells.

It's either that, going through all possible .profile and similar files and injecting source /tmp/something if not present yet, or having the user manually add that to their profile. and that's assuming I can write a .sh script that all shells accept.

Besides the "how to load code command", I'm not still entirely sure how to actually make it work:

  • Currently I keep a shell open in the background, save the /dev/pts/123 in an environment variable which is what code writes to. Problem with this is that I can check whether that character device still exists, but not (easily) check whether it's the extension-owned shell.
  • Another option is using mknode to create a unique pipe, but the problem being that I can't seemingly detect whether the pipe is still being read, without doing weird timeout stuff.
  • Alternatively, use netcat (nc) in listening mode to create a proper Unix socket that outputs to the background terminal. Problem being that netcat isn't actually present on every OS as far as I know.
  • My original idea of forwarding a Unix domain socket over SSH actually seems best, although this would only work with OpenSSH servers. Might actually be best though at this point.

Both issues are already quite complex on their own, so it's taking quite some time and effort to get it working consistently across multiple shells. And I've only tried (and perhaps might even only try) bash and sh, nothing else. I'm assuming that any script I write that's compatible with the Bourne shell (sh) will be source-able by all shells, and that the PROXY_COMMAND/ENV "hack" I'm using now is also good enough.

TL;DR: Lots of work with complex Unix/shell mechanics, but there's at least progress.

I'll probably quickly finish the current half-baked setup I have and push it to a feature branch (or publicly released but only enabled with certain flags), so you can try the code command out yourself and give feedback or, more likely, find bugs. Then I'll continue on #252 before coming back to this.

SchoofsKelvin added a commit that referenced this issue Jun 30, 2021
@SchoofsKelvin
Copy link
Owner

I've pushed an initial prototype to the master branch, you can download the extension from the latest build in this list.

To activate this feature, there are two ways:

  • Add the REMOTE_COMMANDS flag to "sshfs.flags" in your User Settings, like this:
"sshfs.flags": [
    "REMOTE_COMMANDS"
],
  • Add the REMOTE_COMMANDS flag to your (JSON) config's "flags" field, like this:
"sshfs.configs": [
    {
        "name": "some-config",
        "host": "hostname",
        "putty": true,
        "flags": [
            "REMOTE_COMMANDS"
        ]
    }
],

Once that's added, every new connection will make use of the feature, so I recommend reloading the window. When you open a remote terminal through the extension, it should display Injected 'code' alias once and whenever you create an interactive subshell.

The code command expects a single argument, namely a relative or absolute path to a file/directory you want to open. Files will be opened in editors, while directories will be added as workspace folders.

Like I mentioned in my previous comment, the current setup isn't the most elegant or robust, your mileage might vary. Also note that the code command only sends an instruction to the extension and immediately returns. Errors are displayed in VS Code, and the command doesn't wait for the opened editor to be closed. Can't use it for e.g. git for now.

@SchoofsKelvin
Copy link
Owner

The initial prototype is available in v1.21.0 of the extension, so you don't require to manually download and install the built .vsix file. Nothing changed since my last comment though, e.g. it requires the REMOTE_COMMANDS flag and might easily break.

@spanishpear
Copy link
Author

Thanks heaps @SchoofsKelvin - this looks awesome! I'll have a play around 🥳

@abiramen
Copy link

Hi @SchoofsKelvin, this seems to be working wonderfully!

That being said, I was wondering if it'd be possible for the code alias to create a file and open it rather than throw an EntryNotFound error if the file doesn't exist

Thanks 😄

@SchoofsKelvin
Copy link
Owner

@abiramen Can you test the latest build (68 or later) from here? Run the Extensions: Install from VSIX command and select the .vsix artifact file. When trying to open a file that doesn't exist, it should prompt you to create an empty file first.

Mind that it does actually create that empty file. The extension API doesn't seem to allow me to (easily) create an unsaved document for a non-existing URI. Technically I could trick VS Code into allowing this, but hacky and a bit of work.

@abiramen
Copy link

This works great! Thanks @SchoofsKelvin 🎉

@abaj8494
Copy link

Would it be possible to add this functionality for the zsh shell also? If not, perhaps a nudge in the right direction so I can try reverse engineer the work done on the sh and bash shells.

So far the profile config files haven't really helped in deciphering how this works.

@SchoofsKelvin
Copy link
Owner

I've just pushed some commits that should, if I didn't do anything wrong, support most shells. Below is the current list, which I didn't test in-depth yet, but should work for those shells and most shells based on them:

add('sh', setEnvExport, rcInitializePATH, embedSubstitutionsBackticks);
add('bash', setEnvExport, rcInitializePATH, embedSubstitutionsBackticks);
add('rbash', setEnvExport, rcInitializePATH, embedSubstitutionsBackticks);
add('ash', setEnvExport, rcInitializePATH, embedSubstitutionsBackticks);
add('dash', setEnvExport, rcInitializePATH, embedSubstitutionsBackticks);
add('ksh', setEnvExport, rcInitializePATH, embedSubstitutionsBackticks);
add('zsh', setEnvExport, rcInitializePATH, embedSubstitutionsBackticks);
add('fish', setEnvSetGX, rcInitializePATH, embedSubstitutionsFish); // https://fishshell.com/docs/current/tutorial.html#autoloading-functions
add('csh', setEnvSetEnv, rcInitializePATH, embedSubstitutionsBackticks);
add('tcsh', setEnvSetEnv, rcInitializePATH, embedSubstitutionsBackticks);

You can get the latest build from here (build 87 or later) if you want to try it out yourself. I'll release it after some more feedback/testing.

@SchoofsKelvin
Copy link
Owner

More shell support (from my previous comment) added in v1.24.0 of the extension.

@telecasterer
Copy link

telecasterer commented Apr 6, 2022

Hello,

I'm trying to use this on systems where the default shell is /bin/csh, but it doesn't work. It appears that the shell type is not being detected correctly because the extension tries to use the "export" command to set things up instead of "setenv".

EDIT: I switched on logging but I don't see any errors in the SSH FS log.

example terminal output:

Connecting to eda...
export: Command not found.
export: Command not found.
$

So, check the SHELL value...

$ echo $SHELL
/bin/csh

this is actually a link to tcsh:

/bin/csh -> tcsh

Thanks

@SchoofsKelvin
Copy link
Owner

This issue would be easier to solve with debug logs, so please follow these steps:

  • Add DEBUG_SSH2 to the sshfs.flags array in VS Code's User Settings (settings.json)
    e.g. "sshfs.flags": ["DEBUG_SSH2"]
    • See this issue for more information about adding flags
  • If you already have a connection open, close it completely (or even reload the window)
  • Go to Output > SSH FS and copy the log from there after replicating your bug
  • While it should censor passwords/passphrases, I recommend checking it for (other) sensitive data first.
    (especially since DEBUG_SSH2 activates some internal logging, which is less likely to be censored)

That should log which kind of shell it actually thinks you're using. My guess is the detection goes wrong, since csh should get detected:

add('csh', setEnvSetEnv, rcInitializePATH, embedSubstitutionsBackticks);

@telecasterer
Copy link

telecasterer commented Apr 12, 2022

Thanks for the response, here's the log

debug_sshfs.log

I've just noticed that as you suspected there is an error when detecting the shell config :

[ERROR] [createConnection(eda,config)] Error calculating ShellConfig: Error: Command 'echo :::SHELL:$SHELL:SHELL:::' failed with exit code 1:
Bad : modifier in $ (S).
Error: Command 'echo :::SHELL:$SHELL:SHELL:::' failed with exit code 1:
Bad : modifier in $ (S).

I guess this needs to be changed by adding braces:

echo :::SHELL:${SHELL}:SHELL:::

which for csh at least should return: :::SHELL:/bin/csh:SHELL:::

UPDATE: I can confirm that changing $SHELL to ${SHELL} fixes the issue for csh and doesn't cause problems for bash/sh. I've simply updated the minified extension.js file that I already have installed to test this. Would you prefer a pull request?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

6 participants