SSHFS support

This commit is contained in:
Arun Prakash Jana 2019-04-21 00:24:19 +05:30
parent bd29368d4c
commit 882a17a60f
No known key found for this signature in database
GPG key ID: A75979F35C080412
4 changed files with 128 additions and 13 deletions

View file

@ -59,6 +59,7 @@ Have as many scripts as you want to extend the power of `nnn`! Pick from the ava
- [Navigate-as-you-type](#navigate-as-you-type)
- [File indicators](#file-indicators)
- [Configuration](#configuration)
- [SSHFS mounts](#sshfs-mounts)
- [Help](#help)
- [Plugins](#plugins)
- [Troubleshooting](#troubleshooting)
@ -103,7 +104,7 @@ Have as many scripts as you want to extend the power of `nnn`! Pick from the ava
- FreeDesktop compliant trash (needs trash-cli)
- Show copy, move progress on Linux (needs avdcpmv)
- Plugin repository
- Transfer files using lftp
- SSHFS mounts (needs sshfs)
- Batch rename (needs vidir)
- Per-context directory color (default: blue)
- Spawn a shell in the current directory
@ -140,6 +141,8 @@ Have as many scripts as you want to extend the power of `nnn`! Pick from the ava
| vidir (from moreutils) | batch rename dir entries |
| vlock (Linux), bashlock (macOS), lock(1) (BSD) | terminal locker |
| advcpmv (Linux) ([integration](https://github.com/jarun/nnn/wiki/hacking-nnn#show-cp-mv-progress)) | copy, move progress |
| sshfs | mount remote over SSHFS |
| fusermount(3) | SSHFS unmount |
| $EDITOR (overridden by $VISUAL, if defined) | edit files (fallback vi) |
| $PAGER (less, most) | page through files (fallback less) |
| $SHELL | spawn a shell, run some commands (fallback sh) |
@ -264,6 +267,7 @@ Press <kbd>?</kbd> in `nnn` to see the list anytime.
MISC
! ^] Spawn SHELL C Execute entry
R ^V Pick plugin L Lock terminal
c SSHFS mount u Unmount
^P Prompt ^N Note = Launcher
```
@ -380,8 +384,9 @@ The following indicators are used in the detail view:
| `NNN_IDLE_TIMEOUT=300` | idle seconds before locking terminal [default: disabled] |
| `NNN_COPIER='/absolute/path/to/copier'` | system clipboard copier script [default: none] |
| `NNN_PLUGIN_DIR=/home/user/nnn-plugins` | absolute path to plugins dir |
| `NNN_NOTE=/home/user/Dropbox/Public/notes` | path to note file [default: none] |
| `NNN_NOTE=/home/user/Dropbox/notes` | path to note file [default: none] |
| `NNN_TMPFILE=/tmp/nnn` | file to write current open dir path to for cd on quit |
| `NNN_SSHFS_MNT_ROOT=/home/user/.netmnt` | absolute path to SSHFS mount point root |
| `NNN_USE_EDITOR=1` | Open text files in `$EDITOR` (`$VISUAL`, if defined; fallback vi) |
| `NNN_NO_AUTOSELECT=1` | do not auto-select matching dir in _nav-as-you-type_ mode |
| `NNN_RESTRICT_NAV_OPEN=1` | open files on <kbd></kbd>, not <kbd></kbd> or <kbd>l</kbd> |
@ -389,6 +394,33 @@ The following indicators are used in the detail view:
| `NNN_TRASH=1` | trash files to the desktop Trash [default: delete] |
| `NNN_OPS_PROG=1` | show copy, move progress on Linux |
#### SSHFS mounts
To connect to and mount remote shares using SSHFS, `nnn` requires the following:
1. ssh configuration file `~/.ssh/config` should have the host entries. sshfs reads this file.
2. `NNN_SSHFS_MNT_ROOT` should be set to the **absolute path** to the directory under which `nnn` creates the mount point for a host. The mount point is the same as the host name.
Example host entry for a Termux environment on Android device:
```
Host phone
HostName 192.168.0.102
User u0_a117
Port 8022
```
If `NNN_SSHFS_MNT_ROOT` is set to `/home/user/remotes`, the above host `phone` will be mounted at `/home/user/remotes/phone`. `nnn` creates the directory `phone` if it doesn't exist.
To unmount a mount point highlight it in `nnn` (so that it's the current entry) and press the relevant keybind to unmount. It might be a good idea to bookmark `NNN_SSHFS_MNT_ROOT`.
Notes:
1. `nnn` places you inside the mount point after both mount and unmount. This is done so you can ensure the operation completed successfully. To jump back to the last directory, press the usual <kbd>-</kbd>.
2. `nnn` doesn't delete the mount point on unmount. This is to prevent accidental data loss.
More information on [SSHFS](https://wiki.archlinux.org/index.php/SSHFS)
#### Help
$ nnn -h

5
nnn.1
View file

@ -189,6 +189,11 @@ when dealing with the !, e and p commands respectively. A single combination to
export NNN_TMPFILE=/tmp/nnn
.Ed
.Pp
\fBNNN_SSHFS_MNT_ROOT:\fR absolute path to SSHFS mount point root. Mount points are created at this location.
.Bd -literal
export NNN_SSHFS_MNT_ROOT=/home/user/.netmnt`
.Ed
.Pp
\fBNNN_USE_EDITOR:\fR use EDITOR (VISUAL takes preference, preferably CLI, fallback vi) to handle text
files.
.Bd -literal

View file

@ -279,6 +279,7 @@ static char *editor;
static char *pager;
static char *shell;
static char *home;
static char *sshfsmnt;
static blkcnt_t ent_blocks;
static blkcnt_t dir_blocks;
static ulong num_files;
@ -388,15 +389,16 @@ static const char * const messages[] = {
#define NNN_PLUGIN_DIR 5
#define NNN_NOTE 6
#define NNN_TMPFILE 7
#define NNNLVL 8 /* strings end here */
#define NNN_USE_EDITOR 9 /* flags begin here */
#define NNN_NO_AUTOSELECT 10
#define NNN_RESTRICT_NAV_OPEN 11
#define NNN_RESTRICT_0B 12
#define NNN_OPENER_DETACH 13
#define NNN_TRASH 14
#define NNN_SSHFS_MNT_ROOT 8
#define NNNLVL 9 /* strings end here */
#define NNN_USE_EDITOR 10 /* flags begin here */
#define NNN_NO_AUTOSELECT 11
#define NNN_RESTRICT_NAV_OPEN 12
#define NNN_RESTRICT_0B 13
#define NNN_OPENER_DETACH 14
#define NNN_TRASH 15
#ifdef __linux__
#define NNN_OPS_PROG 15
#define NNN_OPS_PROG 16
#endif
static const char * const env_cfg[] = {
@ -408,6 +410,7 @@ static const char * const env_cfg[] = {
"NNN_PLUGIN_DIR",
"NNN_NOTE",
"NNN_TMPFILE",
"NNN_SSHFS_MNT_ROOT",
"NNNLVL",
"NNN_USE_EDITOR",
"NNN_NO_AUTOSELECT",
@ -2387,6 +2390,7 @@ static bool show_help(const char *path)
"1MISC\n"
"9! ^] Spawn SHELL C Execute entry\n"
"9R ^V Pick plugin L Lock terminal\n"
"cc SSHFS mount u Unmount\n"
"b^P Prompt ^N Note = Launcher\n"};
if (g_tmpfpath[0])
@ -2888,10 +2892,8 @@ begin:
/* Can fail when permissions change while browsing.
* It's assumed that path IS a directory when we are here.
*/
if (access(path, R_OK) == -1) {
if (access(path, R_OK) == -1)
printwarn();
goto nochange;
}
populate(path, lastname);
if (interrupted) {
@ -3862,6 +3864,73 @@ nochange:
/* Repopulate as directory content may have changed */
goto begin;
case SEL_SSHFS:
if (!sshfsmnt) {
printwait("set NNN_SSHFS_MNT_ROOT", &presel);
goto nochange;
}
tmp = xreadline(NULL, "Host: ");
if (!tmp[0])
goto nochange;
/* Create the mount point */
mkpath(sshfsmnt, tmp, newpath);
r = mkdir(newpath, 0777);
if (r == -1 && errno != EEXIST) {
printwait(strerror(errno), &presel);
goto nochange;
}
/* Check if directory can be accessed */
if (!xdiraccess(newpath)) {
presel = MSGWAIT;
goto nochange;
}
if (!getutil("sshfs")) {
printwait("sshfs missing", &presel);
goto nochange;
}
/* Convert "Host" to "Host:" */
r = strlen(tmp);
tmp[r] = ':';
tmp[r + 1] = '\0';
/* Connect to remote */
spawn("sshfs", tmp, newpath, NULL, F_NORMAL); // fallthrough
case SEL_UMOUNT:
if (sel == SEL_UMOUNT) {
static char cmd[] = "fusermount3"; /* Arch Linux utility */
static bool found = FALSE;
/* On Ubuntu it's fusermount */
if (!found && !getutil(cmd))
cmd[10] = '\0';
if (!ndents)
goto nochange;
mkpath(path, dents[cur].name, newpath);
if (!xdiraccess(newpath)) {
presel = MSGWAIT;
goto nochange;
}
spawn(cmd, "-u", newpath, NULL, F_NORMAL);
}
lastname[0] = '\0';
/* Save last working directory */
xstrlcpy(lastdir, path, PATH_MAX);
/* Switch to mount point */
xstrlcpy(path, newpath, PATH_MAX);
setdirwatch();
goto begin;
case SEL_QUITCD: // fallthrough
case SEL_QUIT:
for (r = 0; r < CTX_MAX; ++r)
@ -4169,6 +4238,9 @@ int main(int argc, char *argv[])
xstrlcpy(g_cppath + g_tmpfplen - 1, "/.nnncp", PATH_MAX - g_tmpfplen);
}
/* Get SSHFS mountpoint */
sshfsmnt = getenv("NNN_SSHFS_MNT_ROOT");
/* Get the clipboard copier, if set */
copier = getenv(env_cfg[NNN_COPIER]);

View file

@ -85,6 +85,8 @@ enum action {
SEL_NEW,
SEL_RENAME,
SEL_RENAMEALL,
SEL_SSHFS,
SEL_UMOUNT,
SEL_HELP,
SEL_EXEC,
SEL_SHELL,
@ -218,6 +220,10 @@ static struct key bindings[] = {
{ CONTROL('R'), SEL_RENAME },
/* Rename contents of current dir */
{ 'r', SEL_RENAMEALL },
/* Connect to server over SSHFS */
{ 'c', SEL_SSHFS },
/* Disconnect a SSHFS mount point */
{ 'u', SEL_UMOUNT },
/* Show help */
{ '?', SEL_HELP },
/* Execute file */