bash/sources/42_clipboard_server
raw ยท 5611 bytes
SSH_CLIPBOARD_DIR="${SSH_CLIPBOARD_DIR:-$HOME/.cache}"
SSH_CLIPBOARD_COPY_SOCKET="${SSH_CLIPBOARD_COPY_SOCKET:-$SSH_CLIPBOARD_DIR/ssh-clipboard-copy.sock}"
SSH_CLIPBOARD_PASTE_SOCKET="${SSH_CLIPBOARD_PASTE_SOCKET:-$SSH_CLIPBOARD_DIR/ssh-clipboard-paste.sock}"
SSH_CLIPBOARD_PIDFILE="${SSH_CLIPBOARD_PIDFILE:-$SSH_CLIPBOARD_DIR/ssh-clipboard.pid}"
SSH_CLIPBOARD_PASTE_PIDFILE="${SSH_CLIPBOARD_PASTE_PIDFILE:-$SSH_CLIPBOARD_DIR/ssh-clipboard-paste.pid}"
SSH_CLIPBOARD_LOG="${SSH_CLIPBOARD_LOG:-$SSH_CLIPBOARD_DIR/ssh-clipboard.log}"
SSH_CLIPBOARD_CLIENT_ID="$(
printf '%s' "$HOSTNAME" |
tr '[:upper:]' '[:lower:]' |
tr -c 'a-z0-9_.-' '_'
)"
SSH_CLIPBOARD_REMOTE_COPY_SOCKET="/tmp/ssh-clipboard-copy-${SSH_CLIPBOARD_CLIENT_ID}.sock"
SSH_CLIPBOARD_REMOTE_PASTE_SOCKET="/tmp/ssh-clipboard-paste-${SSH_CLIPBOARD_CLIENT_ID}.sock"
function _ssh_clipboard_find_remote_socket {
local type="$1"
local socket found=""
for socket in /tmp/ssh-clipboard-"$type"-*.sock; do
[ -S "$socket" ] || continue
# More than one clipboard client available.
if [ -n "$found" ]; then
return 1
fi
found="$socket"
done
[ -n "$found" ] || return 1
printf '%s\n' "$found"
}
function clipboard_server_running {
local pid
if [ -n "${SSH_CLIPBOARD_REMOTE_COPY_SOCKET:-}" ] &&
[ -S "$SSH_CLIPBOARD_REMOTE_COPY_SOCKET" ]; then
return 0
fi
[[ -f "$SSH_CLIPBOARD_PIDFILE" ]] || return 1
read -r pid < "$SSH_CLIPBOARD_PIDFILE"
[[ "$pid" =~ ^[0-9]+$ ]] || return 1
kill -0 "$pid" 2>/dev/null
}
function init_clipboard_server {
if clipboard_server_running; then
return 0
fi
command -v socat >/dev/null 2>&1 || {
echo "clipboard server: socat is not installed" >&2
return 1
}
case "$OSTYPE" in
darwin*)
[[ -x /usr/bin/pbcopy ]] || {
echo "clipboard server: /usr/bin/pbcopy was not found" >&2
return 1
}
[[ -x /usr/bin/pbpaste ]] || {
echo "clipboard server: /usr/bin/pbpaste was not found" >&2
return 1
}
mkdir -p "$SSH_CLIPBOARD_DIR"
chmod 700 "$SSH_CLIPBOARD_DIR"
rm -f \
"$SSH_CLIPBOARD_COPY_SOCKET" \
"$SSH_CLIPBOARD_PASTE_SOCKET" \
"$SSH_CLIPBOARD_PIDFILE" \
"$SSH_CLIPBOARD_PASTE_PIDFILE"
(
umask 077
# Remote -> local clipboard
socat \
"UNIX-LISTEN:$SSH_CLIPBOARD_COPY_SOCKET,fork,mode=600" \
EXEC:/usr/bin/pbcopy \
>>"$SSH_CLIPBOARD_LOG" 2>&1 &
echo "$!" > "$SSH_CLIPBOARD_PIDFILE"
# Local clipboard -> remote
socat \
"UNIX-LISTEN:$SSH_CLIPBOARD_PASTE_SOCKET,fork,mode=600" \
EXEC:/usr/bin/pbpaste \
>>"$SSH_CLIPBOARD_LOG" 2>&1 &
echo "$!" > "$SSH_CLIPBOARD_PASTE_PIDFILE"
)
;;
cygwin*)
# Eventually:
# copy -> cat > /dev/clipboard
# paste -> cat /dev/clipboard
echo "clipboard server: Cygwin support is not implemented" >&2
return 1
;;
*)
echo "clipboard server: $OSTYPE is not supported" >&2
return 1
;;
esac
}
function stop_clipboard_server {
local pid
if [[ -f "$SSH_CLIPBOARD_PIDFILE" ]]; then
read -r pid < "$SSH_CLIPBOARD_PIDFILE"
[[ "$pid" =~ ^[0-9]+$ ]] && kill "$pid" 2>/dev/null || true
fi
if [[ -f "$SSH_CLIPBOARD_PASTE_PIDFILE" ]]; then
read -r pid < "$SSH_CLIPBOARD_PASTE_PIDFILE"
[[ "$pid" =~ ^[0-9]+$ ]] && kill "$pid" 2>/dev/null || true
fi
rm -f \
"$SSH_CLIPBOARD_COPY_SOCKET" \
"$SSH_CLIPBOARD_PASTE_SOCKET" \
"$SSH_CLIPBOARD_PIDFILE" \
"$SSH_CLIPBOARD_PASTE_PIDFILE"
}
function sshc {
init_clipboard_server || return
local control_socket="/tmp/sshc-%C.sock"
if ! command ssh \
-S "$control_socket" \
-O check \
"$@" \
>/dev/null 2>&1
then
echo "-- cleaning stale clipboard sockets"
command ssh "$@" \
"rm -f \
'$SSH_CLIPBOARD_REMOTE_COPY_SOCKET' \
'$SSH_CLIPBOARD_REMOTE_PASTE_SOCKET'" \
</dev/null || return
echo "-- starting clipboard ssh tunnel"
command ssh \
-M \
-S "$control_socket" \
-o ControlPersist=10 \
-fN \
-R "$SSH_CLIPBOARD_REMOTE_COPY_SOCKET:$SSH_CLIPBOARD_COPY_SOCKET" \
-R "$SSH_CLIPBOARD_REMOTE_PASTE_SOCKET:$SSH_CLIPBOARD_PASTE_SOCKET" \
"$@" || return
fi
echo "-- ssh with clipboard server"
command ssh \
-S "$control_socket" \
"$@"
}
function pbcopy {
local remote_socket
if [ -n "${SSH_CONNECTION:-}" ]; then
remote_socket="$(_ssh_clipboard_find_remote_socket copy)"
if [ -n "$remote_socket" ]; then
command -v socat >/dev/null 2>&1 || {
echo "pbcopy: socat is required for the remote clipboard" >&2
return 1
}
socat - "UNIX-CONNECT:$remote_socket"
return $?
fi
fi
case "$OSTYPE" in
darwin*)
if [ -x /usr/bin/pbcopy ]; then
/usr/bin/pbcopy
else
echo "pbcopy: /usr/bin/pbcopy was not found" >&2
return 1
fi
;;
cygwin*)
cat > /dev/clipboard
;;
*)
echo "pbcopy: no remote clipboard socket is available" >&2
return 1
;;
esac
}
function pbpaste {
local remote_socket
if [ -n "${SSH_CONNECTION:-}" ]; then
remote_socket="$(_ssh_clipboard_find_remote_socket paste)"
if [ -n "$remote_socket" ]; then
command -v socat >/dev/null 2>&1 || {
echo "pbpaste: socat is required for the remote clipboard" >&2
return 1
}
socat - "UNIX-CONNECT:$remote_socket"
return $?
fi
fi
case "$OSTYPE" in
darwin*)
if [ -x /usr/bin/pbpaste ]; then
/usr/bin/pbpaste
else
echo "pbpaste: /usr/bin/pbpaste was not found" >&2
return 1
fi
;;
cygwin*)
cat /dev/clipboard
;;
*)
echo "pbpaste: no remote clipboard socket is available" >&2
return 1
;;
esac
}
if [ -z "${SSH_CONNECTION:-}" ] && init_clipboard_server; then
alias ssh='sshc'
fi