summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErich Eckner <git@eckner.net>2018-12-19 13:43:58 +0100
committerErich Eckner <git@eckner.net>2018-12-19 13:43:58 +0100
commit91c0684b1b65ffe5b7bdceb479f0eea2241ca6a6 (patch)
treeacdfa6d732e765c41f2c7d304c4e82b98036f84a
parent8500a256d3d7c198fd5859f4464dd4d8f25eae93 (diff)
downloaddd-resume-91c0684b1b65ffe5b7bdceb479f0eea2241ca6a6.tar.xz
Makefile newv0.0
-rw-r--r--.gitignore2
-rw-r--r--Makefile57
-rwxr-xr-xdd-resume137
-rw-r--r--dd-resume.in249
4 files changed, 308 insertions, 137 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..6f27ff1
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+dd-resume
+dd-resume.1
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..87cae05
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,57 @@
+#
+# dd-resume - resumably copy with dd via network
+#
+# Copyright (c) 2018 Erich Eckner <opensource at eckner dot net>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+# USA.
+#
+
+DESTDIR =
+BINDIR = /usr/bin
+MANDIR = /usr/share/man
+
+VERSION = 0.0
+
+all: dd-resume dd-resume.1
+
+%: %.in
+ sed " \
+ s/#VERSION#/$(VERSION)/; \
+ s@#BINDIR#@$(BINDIR)@; \
+ s@#HELPTEXT#\(\s\+\)#@ --help \1display this help and exit\n --version\1display version and exit@; \
+ " $< > $@ && \
+ ( [[ "$@" = *.* ]] || chmod +x "$@" )
+
+%.1: %
+ help2man -o "$@" -N --no-discard-stderr "./$<"
+
+.PHONY: install dist clean
+
+install: all
+ install -D -m0755 -t $(DESTDIR)$(BINDIR) dd-resume
+ install -D -m0644 -t $(DESTDIR)$(MANDIR)/man1 dd-resume.1
+
+clean:
+ git clean -x -d -f
+
+dist: clean
+ git status --porcelain 2> /dev/null | grep -q "\S" && (git add .; git commit -m"neue Version: $(VERSION)") || true
+ ! git tag -d v$(VERSION) 2> /dev/null
+ git tag v$(VERSION)
+ git push
+ git push --tags
+
+# End of file
diff --git a/dd-resume b/dd-resume
deleted file mode 100755
index 848c459..0000000
--- a/dd-resume
+++ /dev/null
@@ -1,137 +0,0 @@
-#!/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}"
diff --git a/dd-resume.in b/dd-resume.in
new file mode 100644
index 0000000..8f1d525
--- /dev/null
+++ b/dd-resume.in
@@ -0,0 +1,249 @@
+#!/bin/bash
+
+# dd-resume version #VERSION#
+
+usage() {
+ >&2 printf 'Usage: dd-resume [options]\n'
+ >&2 printf ' copy resumably with dd via network\n\n'
+ >&2 printf 'Options (all options are mandatory unless explicitely stated):\n'
+ >&2 printf ' --input $input-device name of input device\n'
+ >&2 printf ' --host $input-host name of input device'"'"'s host (target only)\n'
+ >&2 printf ' --log-file $log-file name of log file (target only)\n'
+ >&2 printf ' --output $output-device name of output device (target only)\n'
+ >&2 printf ' --port $remote-port port of target host (source only)\n'
+ >&2 printf ' --start $start-position start position for transfer (source only)\n'
+ >&2 printf ' --required print list of required programs and exit\n'
+ >&2 printf '#HELPTEXT# #\n'
+ [ -n "$1" ] && exit $1
+ exit 1
+}
+
+dd_options='bs=2 count=2'
+# bs=1M'
+needed_programs='dd nc ss screen pgrep kill ssh'
+
+eval set -- "$(
+ getopt -o '' \
+ --long input: \
+ --long host: \
+ --long log-file: \
+ --long output: \
+ --long port: \
+ --long start: \
+ --long required \
+ --long help \
+ --long version \
+ -n "$(basename "$0")" \
+ -- "$@" \
+ || echo "usage"
+)"
+
+while true; do
+ case $1 in
+ --input)
+ if [ -n "${input_device}" ]; then
+ >&2 printf 'cannot handle multiple input-devices\n\n'
+ usage
+ fi
+ shift
+ input_device="$1"
+ ;;
+ --host)
+ if [ -n "${host}" ]; then
+ >&2 printf 'cannot handle multiple hosts\n\n'
+ usage
+ fi
+ shift
+ host="$1"
+ ;;
+ --log-file)
+ if [ -n "${log_file}" ]; then
+ >&2 printf 'cannot handle multiple log files\n\n'
+ usage
+ fi
+ shift
+ log_file="$1"
+ ;;
+ --output)
+ if [ -n "${output_device}" ]; then
+ >&2 printf 'cannot handle multiple output devices\n\n'
+ usage
+ fi
+ shift
+ output_device="$1"
+ ;;
+ --port)
+ if [ -n "${remote_port}" ]; then
+ >&2 printf 'cannot handle multiple ports\n\n'
+ usage
+ fi
+ shift
+ remote_port="$1"
+ ;;
+ --start)
+ if [ -n "${start}" ]; then
+ >&2 printf 'cannot handle multiple starts\n\n'
+ usage
+ fi
+ shift
+ start="$1"
+ ;;
+ --required)
+ printf '%s\n' ${needed_programs}
+ exit 0
+ ;;
+ --help)
+ usage 0
+ ;;
+ --version)
+ >&2 printf '%s\n' '#VERSION#'
+ exit 0
+ ;;
+ --)
+ shift
+ break
+ ;;
+ *)
+ >&2 printf 'oops, option "%s" is unkknown\n' "$1"
+ exit 1
+ esac
+ shift
+done
+
+if [ $# -ne 0 ]; then
+ >&2 printf 'too many arguments\n\n'
+ usage
+fi
+
+for needed in ${needed_programs}; do
+ if ! which "${needed}" >/dev/null; then
+ >&2 printf 'please install required program %s\n' "${needed}"
+ exit 1
+ fi
+done
+
+if [ -z "${input_device}" ]; then
+ >&2 printf 'no input device specified\n\n'
+ usage
+fi
+
+if [ -n "${host}" ]; then
+ # was run on the receiver side
+
+ if [ -z "${log_file}" ] || \
+ [ -z "${output_device}" ] || \
+ [ -n "${remote_port}" ] || \
+ [ -n "${start}" ]; then
+ >&2 printf 'conflicting options\n\n'
+ usage
+ fi
+
+ if [ ! -w "${log_file%/*}" ] && [ ! -w "${log_file}" ]; then
+ >&2 printf 'cannot write/create log-file %s\n\n' "${log_file}"
+ usage
+ fi
+
+ if [ ! -w "${output_device}" ]; then
+ >&2 printf 'cannot write to output device %s\n\n' "${output_device}"
+ 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
+
+ previously_running=$(
+ pgrep -x 'dd|nc'
+ )
+
+ printf 'start: %s\n' "${start}" > \
+ "${log_file}"
+
+ screen -d -m bash -c '
+ set +o pipefail
+ nc -l -c | \
+ dd of="'"${output_device}"'" '"${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 | \
+ grep -vxF "$(printf '%s\n' "${previously_running}")"
+ )
+ dd_pid=$(
+ pgrep -x dd | \
+ grep -vxF "$(printf '%s\n' "${previously_running}")"
+ )
+ 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 "${host}" "$0 --input ${input_device} --start ${start} --port ${port}"
+ printf '\nssh-exit: %s\n' $? >>"${log_file}"
+
+else
+ # was run on the sender side
+
+ if [ -n "${log_file}" ] || \
+ [ -n "${output_device}" ] || \
+ [ -z "${remote_port}" ] || \
+ [ -z "${start}" ]; then
+ >&2 printf 'conflicting options\n\n'
+ usage
+ fi
+
+ remote_ip="${SSH_CLIENT%% *}"
+ if [ -z "${remote_ip}" ]; then
+ >&2 printf 'cannot obtain remote ip\n'
+ exit 1
+ fi
+ if [ ! -r "${input_device}" ]; then
+ >&2 printf 'cannot read from %s\n\n' "${input_device}"
+ usage
+ fi
+ set +o pipefail
+ dd if="${input_device}" ${dd_options} skip="${start}" 2>/dev/null | \
+ nc -cn "${remote_ip}" "${remote_port}"
+ exit $?
+
+fi