sshfs fails when remote:dir and (local)dir are the same

1

I want to mount:

remote:/media/user/directory

into:

/media/user/directory

But the mount fails when the remote and local dir names are identical. Issuing the mount command reflects this.

Yet if I use ANY other variation of the same target dir name it works as expected. Examples:

/media/user/.directory               # Succeeds.
/media/user/_directory               # Succeeds.
/media/user/$(hostname)_directory    # Succeeds.

/media/user/directory                # Fails: same as `remote:dir`.

Is there some internal prevention of matching local and remote dir names?

Did I make a syntax error somewhere?

Is the slightly arcane use of this related:

ssh -q $host mount </dev/null

Also:

  • This is a simplified abstract of the actual script, so there is sanity checking not shown here.

  • I typically do not need to include user@ in my ssh hostnames due to ~/.ssh/config aliases, but including them makes no difference.

Code:

#!/bin/bash
hostnameList='
hostnameA
hostnameB
hostnameC
'
while read host; do
  if [[ -n $host && "$host" != "$(hostname)" ]]; then
    availableRemoteDirs=$(ssh -q $host mount < /dev/null \
      | grep "/media" | grep -v "fuse.sshfs" \
      | awk -F' on |:| ' '{print $1 " " $2}' \
      | sed 's/^[^/].*//; s/^.* //'
    )
    while read remoteDir; do
      if [[ -n "$remoteDir" ]]; then
        localDir="${remoteDir}" # FAILS - but is the required name
#       localDir="${remoteDir%/*}/${host}_${remoteDir##*/}"          # works
#       localDir="${remoteDir%/*}/_${remoteDir##*/}"                 # works
        mkdir --verbose --parent "$localDir" &> /dev/null
        sshfs $host:$remoteDir $localDir \
          -o debug,sshfs_debug,idmap=user,nonempty,compression=no &
        sleep 1s
        test=$(mount | grep fuse.sshfs | grep "$localDir")
        echo "test: $test"                    
        if [[ -n $test ]]; then
          echo "OK: $host:$remoteDir -> $localDir"
        else
          echo "Fail"
        fi
      fi
    done <<< "$availableRemoteDirs"
  fi
done <<< "$hostnameList"

As requested: adding error messages/logs.

Note: the absence of error indications at the last two commands, where I have removed the debug options.

Note: in the second successful mount; the text after "unique: 1, success, outsize: 40" is because i refreshed (F5) the Dolphin directory I was looking at the mounts in.

user@betlogbeast:~$ sshfs betlognuc:/media/user/data-backup /media/user/data-backup -o debug,sshfs_debug,idmap=user,nonempty
SSHFS version 2.8
FUSE library version: 2.9.7
nullpath_ok: 0
nopath: 0
utime_omit_ok: 0
executing <ssh> <-x> <-a> <-oClearAllForwardings=yes> <-2> <betlognuc> <-s> <sftp>
Authenticated to 192.168.188.20 ([192.168.188.20]:22).
Server version: 3
Extension: posix-rename@openssh.com <1>
Extension: statvfs@openssh.com <2>
Extension: fstatvfs@openssh.com <2>
Extension: hardlink@openssh.com <1>
Extension: fsync@openssh.com <1>

sent:               0 messages, 0 bytes
received:           0 messages, 0 bytes
rtt min/max/avg:    0ms/0ms/0ms
num connect:        1
user@betlogbeast:~$ Transferred: sent 8308, received 4560 bytes, in 0.3 seconds
Bytes per second: sent 30241.8, received 16598.8
^C
user@betlogbeast:~$ sshfs betlognuc:/media/user/data-backup /media/user/betlognuc_data-backup -o debug,sshfs_debug,idmap=user,nonempty
SSHFS version 2.8
FUSE library version: 2.9.7
nullpath_ok: 0
nopath: 0
utime_omit_ok: 0
executing <ssh> <-x> <-a> <-oClearAllForwardings=yes> <-2> <betlognuc> <-s> <sftp>
Authenticated to 192.168.188.20 ([192.168.188.20]:22).
Server version: 3
Extension: posix-rename@openssh.com <1>
Extension: statvfs@openssh.com <2>
Extension: fstatvfs@openssh.com <2>
Extension: hardlink@openssh.com <1>
Extension: fsync@openssh.com <1>
unique: 1, opcode: INIT (26), nodeid: 0, insize: 56, pid: 0
INIT: 7.26
flags=0x001ffffb
max_readahead=0x00020000
remote_uid = 1000
   INIT: 7.19
   flags=0x00000011
   max_readahead=0x00020000
   max_write=0x00020000
   max_background=0
   congestion_threshold=0
   **unique: 1, success, outsize: 40**
unique: 2, opcode: GETATTR (3), nodeid: 1, insize: 56, pid: 24357
getattr /
[00002] LSTAT
  [00002]          ATTRS       41bytes (0ms)
   unique: 2, success, outsize: 120
unique: 3, opcode: GETXATTR (22), nodeid: 1, insize: 72, pid: 24357
   unique: 3, error: -38 (Function not implemented), outsize: 16
unique: 4, opcode: LOOKUP (1), nodeid: 1, insize: 51, pid: 31277
LOOKUP /.directory
getattr /.directory
[00003] LSTAT
  [00003]          ATTRS       41bytes (0ms)
   NODEID: 2
   unique: 4, success, outsize: 144
unique: 5, opcode: ACCESS (34), nodeid: 2, insize: 48, pid: 31277
access /.directory 02
   unique: 5, success, outsize: 16
unique: 6, opcode: OPEN (14), nodeid: 2, insize: 48, pid: 31277
open flags: 0x8000 /.directory
[00004] OPEN
[00005] LSTAT
  [00004]         HANDLE       17bytes (0ms)
  [00005]          ATTRS       41bytes (0ms)
   open[139944597131952] flags: 0x8000 /.directory
   unique: 6, success, outsize: 32
unique: 7, opcode: READ (15), nodeid: 2, insize: 80, pid: 31277
read[139944597131952] 4096 bytes from 0 flags: 0x8000
[00006] READ
  [00006]           DATA      295bytes (0ms)
   read[139944597131952] 282 bytes from 0
   unique: 7, success, outsize: 298
unique: 8, opcode: GETATTR (3), nodeid: 2, insize: 56, pid: 31277
fgetattr[139944597131952] /.directory
   unique: 8, success, outsize: 120
unique: 9, opcode: FLUSH (25), nodeid: 2, insize: 64, pid: 31277
flush[139944597131952]
   unique: 9, success, outsize: 16
unique: 10, opcode: RELEASE (18), nodeid: 2, insize: 64, pid: 0
release[139944597131952] flags: 0x8000
[00007] CLOSE
   unique: 10, success, outsize: 16
unique: 11, opcode: OPENDIR (27), nodeid: 1, insize: 48, pid: 31280
   unique: 11, success, outsize: 32
unique: 12, opcode: READDIR (28), nodeid: 1, insize: 80, pid: 31280
getdir[0]
[00008] OPENDIR
  [00007]         STATUS       28bytes (0ms)
  [00008]         HANDLE       17bytes (0ms)
[00009] READDIR
[00010] READDIR
  [00009]           NAME    13119bytes (3ms)
[00011] READDIR
[00012] READDIR
  [00010]           NAME     1681bytes (3ms)
[00013] READDIR
[00014] READDIR
  [00011]         STATUS       32bytes (0ms)
  [00012]         STATUS       32bytes (0ms)
  [00013]         STATUS       32bytes (0ms)
  [00014]         STATUS       32bytes (0ms)
[00015] CLOSE
   unique: 12, success, outsize: 4112
unique: 13, opcode: READDIR (28), nodeid: 1, insize: 80, pid: 31280
   unique: 13, success, outsize: 864
unique: 14, opcode: READDIR (28), nodeid: 1, insize: 80, pid: 31280
   unique: 14, success, outsize: 16
unique: 15, opcode: RELEASEDIR (29), nodeid: 1, insize: 64, pid: 0
   unique: 15, success, outsize: 16
  [00015]         STATUS       28bytes (0ms)
^C
Killed by signal 2.
remote host has disconnected
Terminated
user@betlogbeast:~$ ^C
user@betlogbeast:~$ sshfs betlognuc:/media/user/data-backup /media/user/betlognuc_data-backup -o idmap=user,nonempty
user@betlogbeast:~$ sshfs betlognuc:/media/user/data-backup /media/user/data-backup -o idmap=user,nonempty
user@betlogbeast:~$ 

Edit: 2020-05-08--22-47-06

I gave up trying to use identical names, adding the host is actually more useful in many respects anyway. So I settled on that. The scripts I'm using now:

media-locallyMount-allRemoteMediaDirs.sh

#!/bin/bash
# betlog - 2020-04-10--17-59-15
#
# IMPORTANT: https://unix.stackexchange.com/questions/66154/ssh-causes-while-loop-to-stop

# allow_other,default_permissions,
# sshfs_debug

hostnameList='
betlognuc
betlogbrick
betlogbeast
'
f_msg() {
    echo -ne "$m1\\t$m2\\n"
    kdialog --title "$m1" --passivepopup "$m2" 5        
}
mountCount=0
while read host; do
    if [[ -n $host && "$host" != "$(hostname)" ]];then
        availableRemoteDirs=$(ssh -q $host mount </dev/null|grep "/dev/sd"|grep "/media/user/")
        uniqueRemoteDirs=""
        uniqueRemoteDevs=""
        while read remoteDir; do
# this should probably check for shortest path as that is the root one, and longer ones ?might? appesar first?        
            dev=$(echo "$remoteDir"|awk '{print $1}'|sed 's/\/dev\///')
            if [[ ! "$uniqueRemoteDevs" =~ $dev ]];then
                dir=$(echo "$remoteDir"|awk '{print $3}'|sed 's/^[^/].*//; s/^.* //')
                uniqueRemoteDirs+="${dir}\\n"
                uniqueRemoteDevs+="${dev}"
            fi
        done <<< "$availableRemoteDirs"
        uniqueRemoteDevs=""        
        while read remoteDir; do
            if [[ -n "$remoteDir" ]];then
#                 localDir="${remoteDir}" #FAILS
                localDir="${remoteDir%/*}/${host}_${remoteDir##*/}"
                if [[ ! -d "$localDir" ]];then
                    mkdir --verbose --parent "$localDir" &> /dev/null
                    echo -ne "[Desktop Entry]\\nIcon=folder-black" >"${localDir}/.directory"
                fi
                localMountsList=$(mount|grep /media/$USER|grep $(hostname)|sed 's/^.*on //; s/ type.*//')
                if [[ $localMountsList =~ $localDir ]];then
                    m1="ALREADY MOUNTED:"
                    m2="$localDir"
                    f_msg
                else
                    let mountCount+=1
# echo "sshfs $host:$remoteDir $localDir -o  idmap=user,nonempty,compression=no,reconnect,ServerAliveInterval=15,ServerAliveCountMax=3"
                    sshfs $host:$remoteDir $localDir \
                        -o  idmap=user,nonempty,compression=no,reconnect,ServerAliveInterval=15,ServerAliveCountMax=3 &
                    sleep 1s
                    test=$(mount|grep fuse.sshfs|grep "$localDir")
                    if [[ -n $test ]];then
                        m1="MOUNTED"
#                         m2="$host:$remoteDir -> $localDir"
                        m2="$localDir"
                        f_msg
                    else
                        m1="FAil"
#                         m2="$host:$remoteDir -> $localDir"
                        m2="$localDir"
                        f_msg
                    fi
                fi
            fi
        done < <(echo -ne "$uniqueRemoteDirs")
    fi
done <<< "$hostnameList"

if [[ 0 -eq $mountCount ]];then
    m1="NOTHING MOUNTED"
    m2=""
    f_msg
else
    echo "==== FINISHED ===="
fi

media-locallyUNmount-allRemoteMediaDirs.sh

#!/bin/bash
# betlog - 2020-04-11--21-08-49
# unmount sshfs_* mounts from /media/user/
# I HAVE SET /MEDIA/USER TO SUDO CHOWN USER:USER FOR SIMPLICITY
# 
mediaDir="/media/$USER"


f_msg() {
    echo -ne "$m1\\t$m2\\n"
    kdialog --title "$m1" --passivepopup "$m2" 5        
}
mediaDirList="$(find $mediaDir -maxdepth 1 ! -path $mediaDir -type d)" #get dirs, exclude current one
remoteMountsList=$(mount|grep /media/$USER|grep sshfs|sed 's/^.*on //; s/ type.*//')
if [[ -z $remoteMountsList ]];then
    m1="NO SSHFS MOUNTS"
    m2=""
    f_msg
    exit
fi
while read remoteMount; do
#     fusermount -u "$remoteMount" 2> /dev/null
#     fusermount -u "$remoteMount" 2>&1 /tmp/error
    fusermount -u "$remoteMount"
    if [[ $? == 0 ]];then
        m1="UNMOUNTED SSHFS:"
        m2="$remoteMount"
        f_msg
        if [[ -n $(ls -A "$remoteMount" 2> /dev/null|grep -v '.directory') ]];then
            m1="WARNING: DIR NOT EMPTY / DID NOT UNOUNT - UNABLE TO REMOVE:"
            m2="$remoteMount"
            f_msg
        else
            if [[ -z $(mount|grep fuse.sshfs|grep "$remoteMount") ]];then
#                 m1="DIR EMPTY - MOUNT REMOVED - DELETING DIR:"
#                 m2="$remoteMount"
#                 f_msg
                rm "$remoteMount/.directory" 2> /dev/null
                rm -r "$remoteMount"
            fi
        fi
    else
        m1="UNMOUNTING SSHFS ERROR:"
        m2="$remoteMount"
#         m2="$(cat /tmp/error)"
        f_msg
    fi
done <<< "$remoteMountsList"


while read residualDir; do
    [[ "$residualDir" == "$mediaDir" ]] && continue
    if [[ 0 -eq $(find "$residualDir" -maxdepth 9 -type f 2>/dev/null|grep -v '.directory'|wc -l) ]];then
        rm "$residualDir/.directory" 2> /dev/null
        rm -r "$residualDir"
    fi
done <<< "$(find "$mediaDir" -maxdepth 1 -type d)"


echo "==== FINISHED ===="

bash
mount
sshfs
asked on Stack Overflow Apr 19, 2020 by BETLOG • edited May 8, 2020 by BETLOG

1 Answer

0

One possibility is that one of the hosts listed in your hostnameList list is the host that is running the script. In other words, you are trying to mount a directory on the local host over itself.

answered on Stack Overflow Apr 20, 2020 by rtx13

User contributions licensed under CC BY-SA 3.0