Last active
June 22, 2019 13:20
-
-
Save ggets/954b5a1744dbc4b08b5d8edfaae3c3aa to your computer and use it in GitHub Desktop.
SSHFS Mount script for winfsp implementation of sshfs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
################################################################################ | |
### SSHFS Mount script for winfsp implementation of sshfs ### | |
### -by GGetsov ### | |
### ------------------------------------------------------------------------ ### | |
### Requires: Cygwin, bash (with arrays support), Powershell, expect ### | |
### sshfs (WinFSP), jq, procps, grep and find (both preferably GNU) ### | |
################################################################################ | |
arrtest[0]="1"||(echo "Failure: arrays not supported in this version of bash."&&exit 2) | |
#var | |
ver="1.7.0" | |
rev="22.06.2019" | |
declare -A b #binary tools | |
declare -A p #parameters | |
declare -A c #credentials | |
declare -A r #previous instance | |
#fn | |
e(){ | |
${b[echo]} -e "${@}" | |
} | |
err(){ | |
e "${1:-Insufficient arguments. Type \"${0} --help\" to see usage help.}" | |
} | |
b(){ | |
[ -z ${1+x} ]&&err "No commands to autodetect!"&&exit 1 | |
while [[ "${#}" > "0" ]];do | |
t="$(type -t ${1})" | |
if [[ "${t}" == "builtin" ]]||[[ "${t}" == "function" ]]||[[ "${t}" == "alias" ]];then | |
b[${1}]="${1}" | |
elif [[ "${t}" == "file" ]];then | |
b[${1}]="$(type -p ${1})" | |
else | |
err "Could not find the command: ${1}"&&exit 1 | |
fi | |
shift | |
done | |
} | |
pshell (){ | |
cmd /c powershell -NonInteractive -Command - < <(e "${@}") | |
} | |
#tools | |
b type echo printf jq find expect grep sleep sshfs procps taskkill cat | |
#arg | |
[ -z ${1+x} ]&&err&&exit 1 | |
while [[ "${#}" > "0" ]];do | |
case "${1}" in | |
--help) | |
e "CygWin SSHFS mount script by hkr v${ver} (rev${rev})" | |
e " Usage:" | |
e " -d, --disconnect: Disconnect (Optional. Requires 'host' or 'mdir')" | |
e " -h, --host: Host (Mandatory. Format: 'host')" | |
e " -u, --user: SSH user name (Optional. Format: 'user')" | |
e " -r, --rdir: Remote directory (Optional. Format: '/dir'. Default: '/')" | |
e " -m, --mdir: Local directory to mount to (Mandatory. Format: '/dir' (cygwin))" | |
e " -p, --port: Port for SSH (Optional. Default: 22)" | |
e "" | |
e " --test: Only test print the string, don't execute" | |
e "" | |
exit 0 | |
;; | |
-d|--disconnect) | |
p[disconnect]="1" | |
;; | |
-h|--host) | |
[ -z ${2+x} ]||[[ ${2} == -* ]]&&err&&exit 1 | |
p[host]="${2}" | |
shift | |
;; | |
-u|--user) | |
[ -z ${2+x} ]||[[ ${2} == -* ]]&&err&&exit 1 | |
p[user]="${2}" | |
shift | |
;; | |
-p|--port) | |
[ -z ${2+x} ]||[[ ${2} == -* ]]&&err&&exit 1 | |
p[port]="${2}" | |
shift | |
;; | |
-r|--rdir) | |
[ -z ${2+x} ]||[[ ${2} == -* ]]&&err&&exit 1 | |
p[rdir]="${2}" | |
shift | |
;; | |
-m|--mdir) | |
[ -z ${2+x} ]||[[ ${2} == -* ]]&&err&&exit 1 | |
p[mdir]="${2}" | |
shift | |
;; | |
--test) | |
p[test]="1" | |
;; | |
*) | |
;; | |
esac | |
shift | |
done | |
#argcheck: | |
[ -z ${p[disconnect]+x} ]&&{ | |
[ -z ${p[host]+x} ]||[ -z ${p[mdir]+x} ]&&err&&exit 1 | |
}||{ | |
[ -z ${p[host]+x} ]&&[ -z ${p[mdir]+x} ]&&err&&exit 1 | |
} | |
p[user]="${p[user]:=root}" # default user name is 'root' | |
p[rdir]="${p[rdir]:=/}" # default remote dir is '/' | |
p[port]="${p[port]:=22}" # default port is 22 | |
#main | |
p[mdir]="/computer/r/ssh/${p[mdir]}" # subdir of R:\ssh | |
d="0" | |
i="0" | |
s="3" | |
grepmatch="" | |
dispmatch="" | |
[ ! -z ${p[host]+x} ]&&{ | |
[[ "${#grepmatch}" > "0" ]]&&grepmatch="${grepmatch} " | |
[[ "${#dispmatch}" > "0" ]]&&dispmatch="${dispmatch} " | |
grepmatch="${grepmatch}@${p[host]}:${p[rdir]}" | |
dispmatch="${dispmatch}ssh://${p[host]}:${p[rdir]}" | |
} | |
[ ! -z ${p[mdir]+x} ]&&{ | |
[[ "${#grepmatch}" > "0" ]]&&grepmatch="${grepmatch} " | |
[[ "${#dispmatch}" > "0" ]]&&dispmatch="${dispmatch} " | |
grepmatch="${grepmatch}${p[mdir]//\[/\\[}" | |
dispmatch="${dispmatch}${p[mdir]}" | |
} | |
r[proc]="$(${b[procps]} -wC sshfs -o pid,cmd --no-heading 2>/dev/null|${b[grep]} -i "${grepmatch}")" | |
r[proc]="${r[proc]#"${r[proc]%%[!$'\t\r\n ']*}"}" | |
IFS=$'\n' | |
cnt=(${r[proc]}) | |
unset IFS | |
r[cnt]="${#cnt[@]}" | |
r[pid]="${r[proc]%%[$'\t ']*}" | |
r[cmd]="${r[proc]#*[$'\t ']}" | |
[[ "${r[cnt]}" > "0" ]]&&[ -f "/proc/${r[pid]}/winpid" ]&&{ | |
r[winpid]="$(${b[cat]} "/proc/${r[pid]}/winpid")" | |
r[winpid]="${r[winpid]//[$'\t\r\n ']}" | |
} | |
[ ! -z ${p[disconnect]} ]&&{ | |
[[ "${r[cnt]}" > "0" ]]&&{ | |
[[ "${#r[winpid]}" > "0" ]]&&{ | |
e "Disconnecting \"${dispmatch}\"..." | |
${b[taskkill]} /f /pid ${r[winpid]} | |
}||e "Could not get Windows PID to kill the process." | |
}||e "\"${dispmatch}\" not connected." | |
}||{ | |
[[ "${r[cnt]}" > "0" ]]&&e "Already connected. (PID: ${r[pid]})"||{ | |
${b[find]} "${p[mdir]}" -maxdepth 0 >/dev/null 2>&1&&e "\"${p[mdir]}\" is in use or already mounted."||{ | |
while [[ "${d}" == "0" ]]&&[[ "${i}" < "${s}" ]];do | |
o="$(pshell " | |
\$c=\$host.ui.PromptForCredential(\"SSH Password\",\"Enter the SSH server's credentials for 'ssh://${p[host]}:${p[port]}'.\",\"${p[user]}\",\"\") | |
if(\$c -ne \$null){ | |
\$c.GetNetworkCredential()|convertTo-json -compress | |
} | |
")" | |
[ -z ${o:+x} ]&&{ | |
e "Canceled." | |
d="1" | |
}||{ | |
c[u]="$(e ${o}|${b[jq]} -cj '.UserName')" | |
c[p]="$(e ${o}|${b[jq]} -cj '.Password')" | |
user="$p[user]}" | |
[ -z ${c[u]:+x} ]||u="${c[u]}" | |
p[addr]="${u}@${p[host]}:${p[rdir]}" | |
e -n "Connecting to \"ssh://${p[host]}:${p[port]}\" as ${u}... " | |
[ -z ${p[test]+x} ]&&{ | |
${b[expect]} - >/dev/null 2>&1 <<EOBT | |
spawn ${b[sshfs]} "${p[addr]}" {${p[mdir]}} -o port=${p[port]} -o idmap=user -o rellinks -o "StrictHostKeyChecking=no" | |
expect "password:" | |
send ${c[p]}\n\n | |
interact | |
EOBT | |
}||{ | |
c[p]="$(${b[printf]} "%${#c[p]}s")" | |
c[p]="${c[p]// /*}" | |
${b[echo]} | |
${b[echo]} "${b[expect]} - >/dev/null 2>&1 <<EOBT | |
spawn ${b[sshfs]} \"${p[addr]}\" {${p[mdir]}} -o port=${p[port]} -o idmap=user -o rellinks -o \"StrictHostKeyChecking=no\" | |
expect \"password:\" | |
send ${c[p]}\n\n | |
interact | |
EOBT" | |
exit 0 | |
} | |
[[ "${?}" == "0" ]]&&{ | |
${b[sleep]} 1 | |
${b[find]} "${p[mdir]}" -maxdepth 0 >/dev/null 2>&1&&{ | |
e "Connected." | |
d="1" | |
}|| | |
e "($[${i}+1]/${s}) Failed. Could not connect. Wrong password?" | |
}|| | |
e "($[${i}+1]/${s}) Failed. Could not mount. No network or host is not available." | |
} | |
i=$[${i}+1] | |
done | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment