#!/bin/bash # copy resumably with dd via network script_name=$(basename "$0") usage() { >&2 printf 'usage:\n' >&2 printf ' %s in-host in-dev out-dev log-file\n' "${script_name}" >&2 printf ' %s -s in-dev start-position remote-port\n' "${script_name}" exit 1 } dd_options='bs=1M' for needed in dd nc ss screen pgrep kill ssh; do if ! which "${needed}" >/dev/null; then >&2 printf 'please install required program %s\n' "${needed}" exit 1 fi done if [ "x$1" = 'x-s' ]; then shift if [ $# -ne 3 ]; then >&2 printf 'expected 3 arguments, got %s:\n' "$#" >&2 printf '"%s" ' "$@" >&2 printf '\n' usage fi dev="$1" start="$2" remote_ip="${SSH_CLIENT%% *}" if [ -z "${remote_ip}" ]; then >&2 printf 'cannot obtain remote ip\n' exit 1 fi remote_port="$3" if [ ! -r "${dev}" ]; then >&2 printf 'cannot read from %s\n\n' "${dev}" usage fi set +o pipefail dd if="${dev}" ${dd_options} skip="${start}" 2>/dev/null | \ nc -cn "${remote_ip}" "${remote_port}" exit $? fi if [ $# -ne 4 ]; then usage fi remote_host="$1" remote_dev="$2" local_dev="$3" log_file="$4" if [ ! -w "${log_file%/*}" ] && [ ! -w "${log_file}" ]; then >&2 printf 'cannot write/create log-file %s\n\n' "${log_file}" usage fi if [ ! -w "${local_dev}" ]; then >&2 printf 'cannot write to out-dev %s\n\n' "${local_dev}" usage fi start=0 if [ -f "${log_file}" ]; then start=$( sed -n ' 1 { s/^start: // p q } ' "${log_file}" ) copied=$( sed ' s/^\([0-9]\+\)+0 records out$/\1/ t d ' "${log_file}" | \ sort -n | \ tail -n1 ) if [ -n "${copied}" ]; then start=$((start+copied)) fi fi if pgrep -ax dd || pgrep -ax nc; then >&2 printf 'another dd or nc is already running - this won'"'"'t work\n' exit 1 fi printf 'start: %s\n' "${start}" > \ "${log_file}" screen -d -m bash -c ' set +o pipefail nc -l -c | \ dd of="'"${local_dev}"'" '"${dd_options}"' seek='"${start}"' 2>>"'"${log_file}"'" >/dev/null printf '"'"'\nwrite-pipe-exit: %s\n'"'"' $? >>"'"${log_file}"'" ' for i in {1..20}; do if [ -n "${port}" ]; then break elif [ ${i} -gt 1 ]; then sleep 0.1 fi nc_pid=$( pgrep -x nc ) dd_pid=$( pgrep -x dd ) port=$( ss -nlp | \ grep -F ",pid=${nc_pid}," | \ awk '{print $5}' | \ sed 's/^.*://' ) done if [ -z "${port}" ]; then >&2 printf 'could not determine listening port\n' exit 1 fi screen -d -m bash -c ' while kill -SIGUSR1 '"${dd_pid}"'; do sleep 1 done ' ssh "${remote_host}" "${script_name} -s ${remote_dev} ${start} ${port}" printf '\nssh-exit: %s\n' $? >>"${log_file}"