summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErich Eckner <git@eckner.net>2018-12-19 11:23:02 +0100
committerErich Eckner <git@eckner.net>2018-12-19 11:23:02 +0100
commit8500a256d3d7c198fd5859f4464dd4d8f25eae93 (patch)
treec581ead9165b49ae7cd3ff88d2b0b55741e32ffd
downloaddd-resume-8500a256d3d7c198fd5859f4464dd4d8f25eae93.tar.xz
initial commit
-rwxr-xr-xdd-resume137
1 files changed, 137 insertions, 0 deletions
diff --git a/dd-resume b/dd-resume
new file mode 100755
index 0000000..848c459
--- /dev/null
+++ b/dd-resume
@@ -0,0 +1,137 @@
+#!/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}"