summaryrefslogtreecommitdiffstats
path: root/tests/dd
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 16:11:47 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 16:11:47 +0000
commit758f820bcc0f68aeebac1717e537ca13a320b909 (patch)
tree48111ece75cf4f98316848b37a7e26356e00669e /tests/dd
parentInitial commit. (diff)
downloadcoreutils-upstream.tar.xz
coreutils-upstream.zip
Adding upstream version 9.1.upstream/9.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests/dd')
-rwxr-xr-xtests/dd/ascii.sh74
-rwxr-xr-xtests/dd/bytes.sh63
-rwxr-xr-xtests/dd/direct.sh35
-rwxr-xr-xtests/dd/misc.sh127
-rwxr-xr-xtests/dd/no-allocate.sh76
-rwxr-xr-xtests/dd/nocache.sh58
-rwxr-xr-xtests/dd/nocache_eof.sh97
-rwxr-xr-xtests/dd/not-rewound.sh31
-rwxr-xr-xtests/dd/reblock.sh72
-rwxr-xr-xtests/dd/skip-seek-past-dev.sh58
-rwxr-xr-xtests/dd/skip-seek-past-file.sh92
-rwxr-xr-xtests/dd/skip-seek.pl88
-rwxr-xr-xtests/dd/skip-seek2.sh38
-rwxr-xr-xtests/dd/sparse.sh93
-rwxr-xr-xtests/dd/stats.sh76
-rwxr-xr-xtests/dd/stderr.sh43
-rwxr-xr-xtests/dd/unblock-sync.sh35
-rwxr-xr-xtests/dd/unblock.pl59
18 files changed, 1215 insertions, 0 deletions
diff --git a/tests/dd/ascii.sh b/tests/dd/ascii.sh
new file mode 100755
index 0000000..56f3b52
--- /dev/null
+++ b/tests/dd/ascii.sh
@@ -0,0 +1,74 @@
+#!/bin/sh
+# test conv=ascii
+
+# Copyright (C) 2014-2022 Free Software Foundation, Inc.
+
+# 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 3 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, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ dd printf
+
+{
+ # Two lines, EBCDIC " A A" and " A ", followed by all the bytes in order.
+ env printf '\100\301\100\301\100\301\100\100' &&
+ env printf $(env printf '\\%03o' $(seq 0 255));
+} >in || framework_failure_
+
+{
+ # The converted lines, with trailing spaces removed.
+env printf \
+' A A\n A\n'\
+'\000\001\002\003\n\234\011\206\177\n'\
+'\227\215\216\013\n\014\015\016\017\n'\
+'\020\021\022\023\n\235\205\010\207\n'\
+'\030\031\222\217\n\034\035\036\037\n'\
+'\200\201\202\203\n\204\012\027\033\n'\
+'\210\211\212\213\n\214\005\006\007\n'\
+'\220\221\026\223\n\224\225\226\004\n'\
+'\230\231\232\233\n\024\025\236\032\n'\
+'\040\240\241\242\n\243\244\245\246\n'\
+'\247\250\325\056\n\074\050\053\174\n'\
+'\046\251\252\253\n\254\255\256\257\n'\
+'\260\261\041\044\n\052\051\073\176\n'\
+'\055\057\262\263\n\264\265\266\267\n'\
+'\270\271\313\054\n\045\137\076\077\n'\
+'\272\273\274\275\n\276\277\300\301\n'\
+'\302\140\072\043\n\100\047\075\042\n'\
+'\303\141\142\143\n\144\145\146\147\n'\
+'\150\151\304\305\n\306\307\310\311\n'\
+'\312\152\153\154\n\155\156\157\160\n'\
+'\161\162\136\314\n\315\316\317\320\n'\
+'\321\345\163\164\n\165\166\167\170\n'\
+'\171\172\322\323\n\324\133\326\327\n'\
+'\330\331\332\333\n\334\335\336\337\n'\
+'\340\341\342\343\n\344\135\346\347\n'\
+'\173\101\102\103\n\104\105\106\107\n'\
+'\110\111\350\351\n\352\353\354\355\n'\
+'\175\112\113\114\n\115\116\117\120\n'\
+'\121\122\356\357\n\360\361\362\363\n'\
+'\134\237\123\124\n\125\126\127\130\n'\
+'\131\132\364\365\n\366\367\370\371\n'\
+'\060\061\062\063\n\064\065\066\067\n'\
+'\070\071\372\373\n\374\375\376\377\n';
+} >exp || framework_failure_
+
+dd if=in of=out conv=ascii cbs=4 || fail=1
+
+compare exp out \
+ || { od -v -to1 exp > exp2 || framework_failure_;
+ od -v -to1 out > out2 || framework_failure_;
+ compare exp2 out2;
+ fail=1; }
+
+Exit $fail
diff --git a/tests/dd/bytes.sh b/tests/dd/bytes.sh
new file mode 100755
index 0000000..539f041
--- /dev/null
+++ b/tests/dd/bytes.sh
@@ -0,0 +1,63 @@
+#!/bin/sh
+
+# Copyright (C) 2012-2022 Free Software Foundation, Inc.
+
+# 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 3 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, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ dd
+
+echo 0123456789abcdefghijklm > in || framework_failure_
+
+# count bytes
+for operands in "count=14B" "count=14 iflag=count_bytes"; do
+ dd $operands conv=swab < in > out 2> /dev/null || fail=1
+ case $(cat out) in
+ 1032547698badc) ;;
+ *) fail=1 ;;
+ esac
+done
+
+for operands in "iseek=10B" "skip=10 iflag=skip_bytes"; do
+ # skip bytes
+ dd $operands < in > out 2> /dev/null || fail=1
+ case $(cat out) in
+ abcdefghijklm) ;;
+ *) fail=1 ;;
+ esac
+
+ # skip records and bytes from pipe
+ echo 0123456789abcdefghijklm |
+ dd $operands bs=2 > out 2> /dev/null || fail=1
+ case $(cat out) in
+ abcdefghijklm) ;;
+ *) fail=1 ;;
+ esac
+done
+
+truncate -s8 expected2
+printf '\0\0\0\0\0\0\0\0abcdefghijklm\n' > expected
+
+for operands in "oseek=8B" "seek=8 oflag=seek_bytes"; do
+ # seek bytes
+ echo abcdefghijklm |
+ dd $operands bs=5 > out 2> /dev/null || fail=1
+ compare expected out || fail=1
+
+ # Just truncation, no I/O
+ dd $operands bs=5 of=out2 count=0 2> /dev/null || fail=1
+ compare expected2 out2 || fail=1
+done
+
+Exit $fail
diff --git a/tests/dd/direct.sh b/tests/dd/direct.sh
new file mode 100755
index 0000000..640f4c4
--- /dev/null
+++ b/tests/dd/direct.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+# ensure that dd's iflag=direct and oflag=direct work
+
+# Copyright (C) 2009-2022 Free Software Foundation, Inc.
+
+# 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 3 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, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ dd
+
+truncate -s 8192 in || framework_failure_
+dd if=in oflag=direct of=out 2> /dev/null \
+ || skip_ '512 byte aligned O_DIRECT is not supported on this (file) system'
+
+truncate -s 511 short || framework_failure_
+truncate -s 8191 m1 || framework_failure_
+truncate -s 8193 p1 || framework_failure_
+
+for i in short m1 p1; do
+ rm -f out
+ dd if=$i iflag=direct oflag=direct of=out || fail=1
+done
+
+Exit $fail
diff --git a/tests/dd/misc.sh b/tests/dd/misc.sh
new file mode 100755
index 0000000..d20cbac
--- /dev/null
+++ b/tests/dd/misc.sh
@@ -0,0 +1,127 @@
+#!/bin/sh
+# Ensure dd treats '--' properly.
+# Also test some flag values.
+
+# Copyright (C) 1999-2022 Free Software Foundation, Inc.
+
+# 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 3 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, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ dd
+export LC_ALL=C
+
+tmp_in=dd-in
+tmp_in2=dd-in2
+tmp_sym=dd-sym
+tmp_out=dd-out
+
+warn=0
+echo data > $tmp_in || framework_failure_
+ln $tmp_in $tmp_in2 || framework_failure_
+ln -s $tmp_in $tmp_sym || framework_failure_
+
+# check status=none suppresses all output to stderr
+dd status=none if=$tmp_in of=/dev/null 2> err || fail=1
+compare /dev/null err || fail=1
+dd status=none if=$tmp_in skip=2 of=/dev/null 2> err || fail=1
+compare /dev/null err || fail=1
+# check later status=none overrides earlier status=noxfer
+dd status=noxfer status=none if=$tmp_in of=/dev/null 2> err || fail=1
+compare /dev/null err || fail=1
+# check later status=noxfer overrides earlier status=none
+dd status=none status=noxfer if=$tmp_in of=/dev/null 2> err || fail=1
+compare /dev/null err && fail=1
+
+dd if=$tmp_in of=$tmp_out 2> /dev/null || fail=1
+compare $tmp_in $tmp_out || fail=1
+
+rm $tmp_out
+dd -- if=$tmp_in of=$tmp_out 2> /dev/null || fail=1
+compare $tmp_in $tmp_out || fail=1
+
+if dd oflag=append if=$tmp_in of=$tmp_out 2> /dev/null; then
+ compare $tmp_in $tmp_out || fail=1
+fi
+
+case $(cat /dev/stdin <$tmp_in 2>/dev/null) in
+(data)
+ rm -f $tmp_out
+ dd if=/dev/stdin of=$tmp_out <$tmp_in || fail=1
+ compare $tmp_in $tmp_out || fail=1
+esac
+
+if dd iflag=nofollow if=$tmp_in count=0 2> /dev/null; then
+ returns_ 1 dd iflag=nofollow if=$tmp_sym count=0 2> /dev/null || fail=1
+fi
+
+if dd iflag=directory if=. count=0 2> /dev/null; then
+ dd iflag=directory count=0 <. 2> /dev/null || fail=1
+ returns_ 1 dd iflag=directory count=0 <$tmp_in 2> /dev/null || fail=1
+fi
+
+old_ls=$(ls -u --full-time $tmp_in)
+sleep 1
+if dd iflag=noatime if=$tmp_in of=$tmp_out 2> /dev/null; then
+ new_ls=$(ls -u --full-time $tmp_in)
+ if test "x$old_ls" != "x$new_ls"; then
+ cat >&2 <<EOF
+=================================================================
+$0: WARNING!!!
+This operating system has the O_NOATIME file status flag,
+but it is silently ignored in some cases.
+Therefore, dd options like iflag=noatime may be silently ignored.
+=================================================================
+EOF
+ warn=77
+ fi
+fi
+
+if dd oflag=nolinks if=$tmp_in of=$tmp_out 2> /dev/null; then
+ returns_ 1 dd iflag=nolinks if=$tmp_in > /dev/null 2>&1 || fail=1
+ returns_ 1 dd iflag=nolinks < $tmp_in > /dev/null 2>&1 || fail=1
+ dd oflag=nolinks < $tmp_in > $tmp_out 2>&1 || fail=1
+fi
+
+outbytes=$(echo x | dd bs=3 ibs=10 obs=10 conv=sync 2>/dev/null | wc -c)
+test "$outbytes" -eq 3 || fail=1
+
+# A delay is required to trigger a failure.
+# There might be some missed failures but it's unlikely.
+(echo a; sleep .1; echo b) \
+ | dd bs=4 status=noxfer iflag=fullblock >out 2>err || fail=1
+printf 'a\nb\n' > out_ok || framework_failure_
+echo "1+0 records in
+1+0 records out" > err_ok || framework_failure_
+compare out_ok out || fail=1
+compare err_ok err || fail=1
+
+test $fail -eq 0 && fail=$warn
+
+# Check a warning is issued for ambiguous 0x... numbers
+dd if=/dev/null count=0x1 seek=0x1 skip=0x1 status=none 2>err || fail=1
+cat <<\EOF >exp
+dd: warning: '0x' is a zero multiplier; use '00x' if that is intended
+dd: warning: '0x' is a zero multiplier; use '00x' if that is intended
+dd: warning: '0x' is a zero multiplier; use '00x' if that is intended
+EOF
+compare exp err || fail=1
+
+echo "0+0 records in
+0+0 records out" >err_ok || framework_failure_
+big=9999999999999999999999999999999999999999999999999999999999999
+dd if=$tmp_in of=$tmp_out count=00x$big status=noxfer 2>err || fail=1
+compare /dev/null $tmp_out || fail=1
+compare err_ok err || fail=1
+
+Exit $fail
diff --git a/tests/dd/no-allocate.sh b/tests/dd/no-allocate.sh
new file mode 100755
index 0000000..cedfa79
--- /dev/null
+++ b/tests/dd/no-allocate.sh
@@ -0,0 +1,76 @@
+#!/bin/sh
+# make sure that dd doesn't allocate memory unnecessarily
+
+# Copyright (C) 2013-2022 Free Software Foundation, Inc.
+
+# 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 3 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, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ dd
+
+# Determine basic amount of memory needed.
+echo . > f || framework_failure_
+vm=$(get_min_ulimit_v_ timeout 10 dd if=f of=f2 status=none) \
+ || skip_ "this shell lacks ulimit support"
+rm f f2 || framework_failure_
+
+# count and skip are zero, we don't need to allocate memory
+(ulimit -v $vm && dd bs=30M count=0) || fail=1
+(ulimit -v $vm && dd ibs=30M count=0) || fail=1
+(ulimit -v $vm && dd obs=30M count=0) || fail=1
+
+check_dd_seek_alloc() {
+ local file="$1"
+ local buf="$2"
+ test "$file" = 'in' && { dd_file=if; dd_op=skip; }
+ test "$file" = 'out' && { dd_file=of; dd_op=seek; }
+ test "$buf" = 'in' && { dd_buf=ibs; }
+ test "$buf" = 'out' && { dd_buf=obs; }
+ test "$buf" = 'both' && { dd_buf=bs; }
+
+ # Provide input to the "tape"
+ timeout 10 dd count=1 if=/dev/zero of=tape&
+
+ # Allocate buffer and read from the "tape"
+ (ulimit -v $vm \
+ && timeout 10 dd $dd_buf=30M $dd_op=1 count=0 $dd_file=tape)
+ local ret=$?
+
+ # Be defensive in case the tape reader is blocked for some reason
+ test $ret = 124 && framework_failure_
+
+ # This should happen without delay,
+ # and is used to ensure we've not multiple writers to the "tape"
+ wait
+
+ # We want the "tape" reader to fail iff allocating
+ # a large buffer corresponding to the file being read
+ case "$file$buf" in
+ inout|outin) test $ret = 0;;
+ *) test $ret != 0;;
+ esac
+}
+
+# Use a fifo for which seek fails, but read does not.
+# For non seekable output we need to allocate a buffer
+# when simulating seeking with a read.
+if mkfifo tape; then
+ for file in 'in' 'out'; do
+ for buf in 'both' 'in' 'out'; do
+ check_dd_seek_alloc "$file" "$buf" || fail=1
+ done
+ done
+fi
+
+Exit $fail
diff --git a/tests/dd/nocache.sh b/tests/dd/nocache.sh
new file mode 100755
index 0000000..3aee114
--- /dev/null
+++ b/tests/dd/nocache.sh
@@ -0,0 +1,58 @@
+#!/bin/sh
+# Ensure dd handles the 'nocache' flag
+
+# Copyright (C) 2011-2022 Free Software Foundation, Inc.
+
+# 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 3 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, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ dd
+
+# This should not call posix_fadvise
+dd iflag=nocache oflag=nocache if=/dev/null of=/dev/null || fail=1
+
+# We should get an error for trying to process a pipe
+dd count=0 | returns_ 1 dd iflag=nocache count=0 || fail=1
+
+# O_DIRECT is orthogonal to drop cache so mutually exclusive
+returns_ 1 dd iflag=nocache,direct if=/dev/null || fail=1
+
+# The rest ensure that the documented uses cases
+# proceed without error
+for f in ifile ofile; do
+ dd if=/dev/zero of=$f conv=fdatasync count=100 || framework_failure_
+done
+
+# Advise to drop cache for whole file
+if ! dd if=ifile iflag=nocache count=0 2>err; then
+ # We could check for 'Operation not supported' in err here,
+ # but that was seen to be brittle. HPUX returns ENOTTY for example.
+ # So assume that if this basic operation fails, it's due to lack
+ # of support by the system.
+ warn_ 'skipping part; this file system lacks support for posix_fadvise()'
+ skip=1
+fi
+
+if test "$skip" != 1; then
+ # Ensure drop cache for whole file
+ dd of=ofile oflag=nocache conv=notrunc,fdatasync count=0 || fail=1
+
+ # Drop cache for part of file
+ dd if=ifile iflag=nocache skip=10 count=10 of=/dev/null || fail=1
+
+ # Stream data just using readahead cache
+ dd if=ifile of=ofile iflag=nocache oflag=nocache || fail=1
+fi
+
+Exit $fail
diff --git a/tests/dd/nocache_eof.sh b/tests/dd/nocache_eof.sh
new file mode 100755
index 0000000..7de765c
--- /dev/null
+++ b/tests/dd/nocache_eof.sh
@@ -0,0 +1,97 @@
+#!/bin/sh
+# Ensure dd invalidates to EOF when appropriate
+
+# Copyright (C) 2017-2022 Free Software Foundation, Inc.
+
+# 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 3 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, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ dd
+require_strace_ fadvise64,fadvise64_64
+
+head -c1234567 /dev/zero > in.f || framework_failure_
+
+# Check basic operation or skip.
+# We could check for 'Operation not supported' error here,
+# but that was seen to be brittle. HPUX returns ENOTTY for example.
+# So assume that if this basic operation fails, it's due to lack
+# of support by the system.
+dd if=in.f iflag=nocache count=0 ||
+ skip_ 'this file system lacks support for posix_fadvise()'
+
+strace_dd() {
+ strace -o dd.strace -e fadvise64,fadvise64_64 dd status=none "$@" || fail=1
+}
+
+advised_to_eof() {
+ grep -F ' 0, POSIX_FADV_DONTNEED' dd.strace >/dev/null
+}
+
+# The commented fadvise64 calls are what are expected with
+# a 4KiB page size and 128KiB IO_BUFSIZE.
+
+strace_dd if=in.f of=out.f bs=1M oflag=nocache,sync
+#fadvise64(1, 0, 1048576, POSIX_FADV_DONTNEED) = 0
+#fadvise64(1, 1048576, 131072, POSIX_FADV_DONTNEED) = 0
+#fadvise64(1, 1179648, 0, POSIX_FADV_DONTNEED) = 0
+advised_to_eof || fail=1
+
+strace_dd if=in.f count=0 iflag=nocache
+#fadvise64(0, 0, 0, POSIX_FADV_DONTNEED) = 0
+advised_to_eof || fail=1
+
+strace_dd if=in.f of=/dev/null iflag=nocache skip=10 count=300
+#fadvise64(0, 5120, 131072, POSIX_FADV_DONTNEED) = 0
+#fadvise64(0, 136192, 22528, POSIX_FADV_DONTNEED) = 0
+returns_ 1 advised_to_eof || fail=1
+
+strace_dd if=in.f of=/dev/null iflag=nocache bs=1M count=3000
+#fadvise64(0, 0, 1048576, POSIX_FADV_DONTNEED) = 0
+#fadvise64(0, 1048576, 131072, POSIX_FADV_DONTNEED) = 0
+#fadvise64(0, 1179648, 0, POSIX_FADV_DONTNEED) = 0
+advised_to_eof || fail=1
+
+strace_dd if=in.f of=/dev/null bs=1M count=1 iflag=nocache
+#fadvise64(0, 0, 1048576, POSIX_FADV_DONTNEED) = 0
+returns_ 1 advised_to_eof || fail=1
+
+strace_dd if=in.f of=out.f bs=1M iflag=nocache oflag=nocache,sync
+#fadvise64(0, 0, 1048576, POSIX_FADV_DONTNEED) = 0
+#fadvise64(1, 0, 1048576, POSIX_FADV_DONTNEED) = 0
+#fadvise64(0, 1048576, 131072, POSIX_FADV_DONTNEED) = 0
+#fadvise64(1, 1048576, 131072, POSIX_FADV_DONTNEED) = 0
+#fadvise64(0, 1179648, 0, POSIX_FADV_DONTNEED) = 0
+#fadvise64(1, 1179648, 0, POSIX_FADV_DONTNEED) = 0
+advised_to_eof || fail=1
+
+# Ensure sub page size offsets are handled.
+# I.e., only page aligned offsets are sent to fadvise.
+if ! strace -o dd.strace -e fadvise64,fadvise64_64 dd status=none \
+ if=in.f of=out.f bs=1M oflag=direct oseek=512B; then
+ warn_ '512 byte aligned O_DIRECT is not supported on this (file) system'
+ # The current file system may not support O_DIRECT,
+ # or older XFS had a page size alignment requirement
+else
+ #The first call is redundant but inconsequential
+ #fadvise64(1, 1048576, 0, POSIX_FADV_DONTNEED) = 0
+ #fadvise64(1, 1048576, 0, POSIX_FADV_DONTNEED) = 0
+ advised_to_eof || fail=1
+
+ strace_dd if=in.f of=out.f bs=1M oflag=direct
+ #fadvise64(1, 1048576, 0, POSIX_FADV_DONTNEED) = 0
+ #fadvise64(1, 1048576, 0, POSIX_FADV_DONTNEED) = 0
+ advised_to_eof || fail=1
+fi
+
+Exit $fail
diff --git a/tests/dd/not-rewound.sh b/tests/dd/not-rewound.sh
new file mode 100755
index 0000000..60c93c0
--- /dev/null
+++ b/tests/dd/not-rewound.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+# Make sure dd does the right thing when the input file descriptor
+# is not rewound.
+
+# Copyright (C) 2000-2022 Free Software Foundation, Inc.
+
+# 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 3 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, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ dd
+
+
+echo abcde > in
+(dd skip=1 count=1 bs=1; dd skip=1 bs=1) < in > out 2> /dev/null || fail=1
+case $(cat out) in
+ bde) ;;
+ *) fail=1 ;;
+esac
+
+Exit $fail
diff --git a/tests/dd/reblock.sh b/tests/dd/reblock.sh
new file mode 100755
index 0000000..ce3716c
--- /dev/null
+++ b/tests/dd/reblock.sh
@@ -0,0 +1,72 @@
+#!/bin/sh
+# test dd reblocking vs. bs=
+
+# Copyright (C) 2008-2022 Free Software Foundation, Inc.
+
+# 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 3 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, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ dd
+
+# 2 short reads -> 1 full write + 1 partial write
+cat <<\EOF > exp-reblock || framework_failure_
+0+2 records in
+1+1 records out
+4 bytes copied
+EOF
+
+# 2 short reads -> 2 partial writes
+cat <<\EOF > exp-no-reblock || framework_failure_
+0+2 records in
+0+2 records out
+4 bytes copied
+EOF
+
+
+# Use a fifo rather than a pipe in the tests below
+# so that the producer (printf subshell) will wait
+# until the consumer (dd) opens the fifo therefore
+# increasing the chance that dd will read the data
+# from each printf separately.
+mkfifo_or_skip_ dd.fifo
+
+dd_reblock_1()
+{
+ local delay="$1"
+
+ # ensure that dd reblocks when bs= is not specified
+ dd ibs=3 obs=3 if=dd.fifo > out 2> err&
+ (printf 'ab'; sleep $delay; printf 'cd') > dd.fifo
+ wait #for dd to complete
+ sed 's/,.*//' err > k && mv k err
+ compare exp-reblock err
+}
+
+retry_delay_ dd_reblock_1 .1 6 || fail=1
+
+dd_reblock_2()
+{
+ local delay="$1"
+
+ # Demonstrate that bs=N supersedes even following ibs= and obs= settings.
+ dd bs=3 ibs=1 obs=1 if=dd.fifo > out 2> err&
+ (printf 'ab'; sleep $delay; printf 'cd') > dd.fifo
+ wait #for dd to complete
+ sed 's/,.*//' err > k && mv k err
+ compare exp-no-reblock err
+}
+
+retry_delay_ dd_reblock_2 .1 6 || fail=1
+
+Exit $fail
diff --git a/tests/dd/skip-seek-past-dev.sh b/tests/dd/skip-seek-past-dev.sh
new file mode 100755
index 0000000..55c8741
--- /dev/null
+++ b/tests/dd/skip-seek-past-dev.sh
@@ -0,0 +1,58 @@
+#!/bin/sh
+# test diagnostics are printed immediately when seeking beyond device.
+
+# Copyright (C) 2008-2022 Free Software Foundation, Inc.
+
+# 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 3 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, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ dd
+
+# need write access to local device
+# (even though we don't actually write anything)
+require_root_
+require_local_dir_
+
+get_device_size() {
+ BLOCKDEV=blockdev
+ $BLOCKDEV -V >/dev/null 2>&1 || BLOCKDEV=/sbin/blockdev
+ $BLOCKDEV --getsize64 "$1"
+}
+
+
+# Get path to device the current dir is on.
+# Note df can only get fs size, not device size.
+device=$(df --output=source . | tail -n1) || framework_failure_
+
+dev_size=$(get_device_size "$device") ||
+ skip_ "failed to determine size of $device"
+
+# Don't use shell arithmetic as older versions of dash use longs
+DEV_OFLOW=$(expr $dev_size + 1) || framework_failure_
+
+timeout 10 dd bs=1 skip=$DEV_OFLOW count=0 status=noxfer < "$device" 2> err
+test "$?" = "1" || fail=1
+echo "dd: 'standard input': cannot skip: Invalid argument
+0+0 records in
+0+0 records out" > err_ok || framework_failure_
+compare err_ok err || fail=1
+
+timeout 10 dd bs=1 seek=$DEV_OFLOW count=0 status=noxfer > "$device" 2> err
+test "$?" = "1" || fail=1
+echo "dd: 'standard output': cannot seek: Invalid argument
+0+0 records in
+0+0 records out" > err_ok || framework_failure_
+compare err_ok err || fail=1
+
+Exit $fail
diff --git a/tests/dd/skip-seek-past-file.sh b/tests/dd/skip-seek-past-file.sh
new file mode 100755
index 0000000..e952448
--- /dev/null
+++ b/tests/dd/skip-seek-past-file.sh
@@ -0,0 +1,92 @@
+#!/bin/sh
+# test diagnostics are printed when seeking too far in seekable files.
+
+# Copyright (C) 2008-2022 Free Software Foundation, Inc.
+
+# 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 3 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, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ dd
+require_sparse_support_ # for 'truncate --size=$OFF_T_MAX'
+eval $(getlimits) # for OFF_T limits
+export LC_ALL=C
+
+printf "1234" > file || framework_failure_
+
+echo "\
+dd: 'standard input': cannot skip to specified offset
+0+0 records in
+0+0 records out" > skip_err || framework_failure_
+
+# skipping beyond number of blocks in file should issue a warning
+dd bs=1 skip=5 count=0 status=noxfer < file 2> err || fail=1
+compare skip_err err || fail=1
+
+# skipping beyond number of bytes in file should issue a warning
+dd bs=3 skip=2 count=0 status=noxfer < file 2> err || fail=1
+compare skip_err err || fail=1
+
+# skipping beyond number of blocks in pipe should issue a warning
+cat file | dd bs=1 skip=5 count=0 status=noxfer 2> err || fail=1
+compare skip_err err || fail=1
+
+# skipping beyond number of bytes in pipe should issue a warning
+cat file | dd bs=3 skip=2 count=0 status=noxfer 2> err || fail=1
+compare skip_err err || fail=1
+
+# Check seeking beyond file already offset into
+# skipping beyond number of blocks in file should issue a warning
+(dd bs=1 skip=1 count=0 2>/dev/null &&
+ dd bs=1 skip=4 status=noxfer 2> err) < file || fail=1
+compare skip_err err || fail=1
+
+# Check seeking beyond file already offset into
+# skipping beyond number of bytes in file should issue a warning
+(dd bs=1 skip=1 count=0 2>/dev/null &&
+ dd bs=2 skip=2 status=noxfer 2> err) < file || fail=1
+compare skip_err err || fail=1
+
+# seeking beyond end of file is OK
+dd bs=1 seek=5 count=0 status=noxfer > file 2> err || fail=1
+echo "0+0 records in
+0+0 records out" > err_ok || framework_failure_
+compare err_ok err || fail=1
+
+# skipping > OFF_T_MAX should fail immediately
+dd bs=1 skip=$OFF_T_OFLOW count=0 status=noxfer < file 2> err && fail=1
+# error message should be "... invalid number: strerror(EOVERFLOW)"
+grep "invalid number:" err >/dev/null || fail=1
+dd bs=1 skip=${OFF_T_OFLOW}x$OFF_T_OFLOW count=0 status=noxfer < file 2> err &&
+ fail=1
+grep "invalid number:" err >/dev/null || fail=1
+
+# skipping > max file size should fail immediately
+if ! truncate --size=$OFF_T_MAX in 2>/dev/null; then
+ # truncate is to ensure file system doesn't actually support OFF_T_MAX files
+ dd bs=1 skip=$OFF_T_MAX count=0 status=noxfer < file 2> err \
+ && lseek_ok=yes \
+ || lseek_ok=no
+
+ if test $lseek_ok = yes; then
+ # On Solaris 10 at least, lseek(>max file size) succeeds,
+ # so just check for the skip warning.
+ compare skip_err err || fail=1
+ else
+ # On Linux kernels at least, lseek(>max file size) fails.
+ # error message should be "... cannot skip: strerror(EINVAL)"
+ grep "cannot skip:" err >/dev/null || fail=1
+ fi
+fi
+
+Exit $fail
diff --git a/tests/dd/skip-seek.pl b/tests/dd/skip-seek.pl
new file mode 100755
index 0000000..0fcb1cf
--- /dev/null
+++ b/tests/dd/skip-seek.pl
@@ -0,0 +1,88 @@
+#!/usr/bin/perl
+# Test dd's skip and seek options.
+
+# Copyright (C) 2000-2022 Free Software Foundation, Inc.
+
+# 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 3 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, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $program_name = $0) =~ s|.*/||;
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+my $out = 'out';
+
+my @Tests =
+ (
+ [
+ 'sk-seek1',
+ qw (bs=1 skip=1 seek=2 conv=notrunc count=3 status=noxfer of=@AUX@ < ),
+ {IN=> '0123456789abcdef'},
+ {AUX=> 'zyxwvutsrqponmlkji'},
+ {OUT=> ''},
+ {ERR=> "3+0 records in\n3+0 records out\n"},
+ {CMP=> ['zy123utsrqponmlkji', {'@AUX@'=> undef}]},
+ ],
+ [
+ 'sk-seek2',
+ qw (bs=5 skip=1 seek=1 conv=notrunc count=1 status=noxfer of=@AUX@ < ),
+ {IN=> '0123456789abcdef'},
+ {AUX=> 'zyxwvutsrqponmlkji'},
+ {OUT=> ''},
+ {ERR=> "1+0 records in\n1+0 records out\n"},
+ {CMP=> ['zyxwv56789ponmlkji', {'@AUX@'=> undef}]},
+ ],
+ [
+ 'sk-seek3',
+ qw (bs=5 skip=1 seek=1 count=1 status=noxfer of=@AUX@ < ),
+ {IN=> '0123456789abcdef'},
+ {AUX=> 'zyxwvutsrqponmlkji'},
+ {OUT=> ''},
+ {ERR=> "1+0 records in\n1+0 records out\n"},
+ {CMP=> ['zyxwv56789', {'@AUX@'=> undef}]},
+ ],
+ [
+ # Before fileutils-4.0.45, the last 10 bytes of output
+ # were these "\0\0\0\0\0\0\0\0 ".
+ 'block-sync-1', qw(ibs=10 cbs=10 status=noxfer), 'conv=block,sync', '<',
+ {IN=> "01234567\nabcdefghijkl\n"},
+ {OUT=> "01234567 abcdefghij "},
+ {ERR=> "2+1 records in\n0+1 records out\n1 truncated record\n"},
+ ],
+ [
+ # Before coreutils-5.93, this would output just "c\n".
+ 'sk-seek4', qw(bs=1 skip=1 status=noxfer),
+ {IN_PIPE=> "abc\n"},
+ {OUT=> "bc\n"},
+ {ERR=> "3+0 records in\n3+0 records out\n"},
+ ],
+ [
+ # Check that iseek and oseek aliases work too.
+ 'sk-seek5',
+ qw (bs=1 iseek=1 oseek=2 conv=notrunc count=3 status=noxfer of=@AUX@ < ),
+ {IN=> '0123456789abcdef'},
+ {AUX=> 'zyxwvutsrqponmlkji'},
+ {OUT=> ''},
+ {ERR=> "3+0 records in\n3+0 records out\n"},
+ {CMP=> ['zy123utsrqponmlkji', {'@AUX@'=> undef}]},
+ ],
+ );
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $prog = 'dd';
+my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;
diff --git a/tests/dd/skip-seek2.sh b/tests/dd/skip-seek2.sh
new file mode 100755
index 0000000..779e1b2
--- /dev/null
+++ b/tests/dd/skip-seek2.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+# show how to skip an amount that is smaller than the nominal block size.
+# There's a more realistic example in the documentation.
+
+# Copyright (C) 2000-2022 Free Software Foundation, Inc.
+
+# 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 3 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, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ dd
+
+
+echo LA:3456789abcdef > in || framework_failure_
+(dd bs=1 skip=3 count=0 && dd bs=5) < in > out 2> /dev/null || fail=1
+case $(cat out) in
+ 3456789abcdef) ;;
+ *) fail=1 ;;
+esac
+
+echo LA:3456789abcdef > in || framework_failure_
+(dd bs=1 skip=3 count=0 && dd bs=5 count=2) < in > out 2> /dev/null || fail=1
+case $(cat out) in
+ 3456789abc) ;;
+ *) fail=1 ;;
+esac
+
+Exit $fail
diff --git a/tests/dd/sparse.sh b/tests/dd/sparse.sh
new file mode 100755
index 0000000..87477a0
--- /dev/null
+++ b/tests/dd/sparse.sh
@@ -0,0 +1,93 @@
+#!/bin/sh
+
+# Copyright (C) 2012-2022 Free Software Foundation, Inc.
+
+# 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 3 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, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ dd
+is_local_dir_ . || very_expensive_
+require_sparse_support_
+
+# Ensure basic sparse generation works
+truncate -s1M sparse
+dd bs=32K if=sparse of=sparse.dd conv=sparse
+test $(stat -c %s sparse) = $(stat -c %s sparse.dd) || fail=1
+
+# Demonstrate that conv=sparse with oflag=append,
+# will do ineffective seeks in the output
+printf 'a\000\000b' > file.in
+printf 'ab' > exp
+dd if=file.in bs=1 conv=sparse oflag=append > out
+compare exp out || fail=1
+
+# Demonstrate conv=sparse with conv=notrunc,
+# where data in file.out is not overwritten with NULs
+printf '____' > out
+printf 'a__b' > exp
+dd if=file.in bs=1 conv=sparse,notrunc of=out
+compare exp out || fail=1
+
+# Ensure we fall back to write if seek fails
+dd if=file.in bs=1 conv=sparse | cat > file.out
+cmp file.in file.out || fail=1
+
+# Setup for block size tests: create a 3MiB file with a 1MiB
+# stretch of NUL bytes in the middle.
+rm -f file.in
+dd if=/dev/urandom of=file.in bs=1M count=3 iflag=fullblock || fail=1
+dd if=/dev/zero of=file.in bs=1M count=1 seek=1 conv=notrunc || fail=1
+
+kb_alloc() { du -k "$1"|cut -f1; }
+
+# sync out data for async allocators like NFS/BTRFS
+# sync file.in || fail=1
+
+# If our just-created input file appears to be too small,
+# skip the remaining tests. On at least Solaris 10 with NFS,
+# file.in is reported to occupy <= 1KiB for about 50 seconds
+# after its creation.
+if test $(kb_alloc file.in) -gt 3000; then
+
+ # Ensure NUL blocks smaller than the *output* block size are not made sparse.
+ # Here, with a 2MiB block size, dd's conv=sparse must *not* introduce a hole.
+ dd if=file.in of=file.out ibs=1M obs=2M conv=sparse || fail=1
+
+ # Intermittently BTRFS returns 0 allocation for file.out unless synced
+ sync file.out || framework_failure_
+ test 2500 -lt $(kb_alloc file.out) || fail=1
+
+ # Note we recreate a sparse file first to avoid
+ # speculative preallocation seen in XFS, where a write() that
+ # extends a file can preallocate some extra space that
+ # a subsequent seek will not convert to a hole.
+ rm -f file.out
+ truncate --size=3M file.out
+
+ # Ensure that this 1MiB *output* block of NULs *is* converted to a hole.
+ dd if=file.in of=file.out ibs=2M obs=1M conv=sparse,notrunc
+ if test $(kb_alloc file.out) -ge 2500; then
+ # Double check the failure by creating a sparse file in
+ # the traditional manner for comparison, as we're not guaranteed
+ # that seek=1M will create a hole. apfs on darwin 19.2.0 for example
+ # was seen to not to create holes < 16MiB.
+ dd if=file.in of=manual.out bs=1M count=1 || fail=1
+ dd if=file.in of=manual.out bs=1M count=1 seek=2 conv=notrunc || fail=1
+
+ test $(kb_alloc file.out) -eq $(kb_alloc manual.out) || fail=1
+ fi
+
+fi
+
+Exit $fail
diff --git a/tests/dd/stats.sh b/tests/dd/stats.sh
new file mode 100755
index 0000000..94df3bd
--- /dev/null
+++ b/tests/dd/stats.sh
@@ -0,0 +1,76 @@
+#!/bin/sh
+# Check stats output for SIG{INFO,USR1} and status=progress
+
+# Copyright (C) 2014-2022 Free Software Foundation, Inc.
+
+# 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 3 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, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ dd
+require_trap_signame_
+
+kill -l | grep 'INFO' && SIGINFO='INFO' || SIGINFO='USR1'
+
+# This to avoid races in the USR1 case
+# as the dd process will terminate by default until
+# it has its handler enabled.
+trap '' $SIGINFO
+
+mkfifo_or_skip_ fifo
+
+# Terminate any background processes
+cleanup_()
+{
+ kill $pid 2>/dev/null
+ kill $pid2 2>/dev/null
+ wait
+}
+
+for open in '' '1'; do
+ > err || framework_failure_
+
+ # Run dd with the fullblock iflag to avoid short reads
+ # which can be triggered by reception of signals
+ dd iflag=fullblock if=/dev/zero of=fifo count=50 bs=5000000 2>err & pid=$!
+
+ # Note if we sleep here we give dd a chance to exec and block on open.
+ # Otherwise we're probably testing SIG_IGN in the forked shell or early dd.
+ test "$open" && sleep .1
+
+ # dd will block on open until fifo is opened for reading.
+ # Timeout in case dd goes away erroneously which we check for below.
+ timeout 60 sh -c 'wc -c < fifo > nwritten' & pid2=$!
+
+ # Send lots of signals immediately to ensure dd not killed due
+ # to race setting handler, or blocking on open of fifo.
+ # Many signals also check that short reads are handled.
+ until ! kill -s $SIGINFO $pid 2>/dev/null; do
+ sleep .01
+ done
+
+ wait
+
+ # Ensure all data processed and at least last status written
+ grep '250000000 bytes (250 MB, 238 MiB) copied' err || { cat err; fail=1; }
+done
+
+progress_output()
+{
+ { sleep $1; echo 1; } | dd bs=1 status=progress of=/dev/null 2>err
+ # Progress output should be for "byte copied", while final is "bytes ..."
+ grep 'byte copied' err
+}
+retry_delay_ progress_output 1 4 || { cat err; fail=1; }
+
+Exit $fail
diff --git a/tests/dd/stderr.sh b/tests/dd/stderr.sh
new file mode 100755
index 0000000..93dd5a9
--- /dev/null
+++ b/tests/dd/stderr.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+# Ensure dd recognizes failure to write to stderr.
+
+# Copyright (C) 2009-2022 Free Software Foundation, Inc.
+
+# 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 3 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, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ dd
+
+p=$abs_top_builddir
+
+
+# Ensure this exits successfully, even though stderr is closed,
+# because it generates no stderr output.
+dd --help >/dev/null 2>&- || fail=1
+
+# If 2>&- works, ensure this fails, because stderr is closed and it
+# *does* generate output. 2>&- apparently does not work in HP-UX 11.23.
+# This test is ineffective unless /dev/stderr also works.
+# This exposes a failure present in 6.11 through 7.5.
+if "$p/src/test" -w /dev/stderr 2>/dev/null &&
+ "$p/src/test" ! -w /dev/stderr 2>&-; then
+ : | returns_ 1 dd 2>&- || fail=1
+fi
+
+# Likewise for /dev/full, if /dev/full works.
+if test -w /dev/full && test -c /dev/full; then
+ : | returns_ 1 dd 2>/dev/full || fail=1
+fi
+
+Exit $fail
diff --git a/tests/dd/unblock-sync.sh b/tests/dd/unblock-sync.sh
new file mode 100755
index 0000000..213dea0
--- /dev/null
+++ b/tests/dd/unblock-sync.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+# Ensure that dd conv=unblock,sync works.
+
+# Copyright (C) 2003-2022 Free Software Foundation, Inc.
+
+# 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 3 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, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ dd
+
+printf 000100020003xx > in || framework_failure_
+
+
+dd cbs=4 ibs=4 conv=unblock,sync < in > out 2> /dev/null || fail=1
+cat <<\EOF > exp || framework_failure_
+0001
+0002
+0003
+xx
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/dd/unblock.pl b/tests/dd/unblock.pl
new file mode 100755
index 0000000..08701b2
--- /dev/null
+++ b/tests/dd/unblock.pl
@@ -0,0 +1,59 @@
+#!/usr/bin/perl
+# Exercise dd's conv=unblock mode
+
+# Copyright (C) 2009-2022 Free Software Foundation, Inc.
+
+# 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 3 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, see <https://www.gnu.org/licenses/>.
+
+use strict;
+
+(my $program_name = $0) =~ s|.*/||;
+
+# Turn off localization of executable's output.
+@ENV{qw(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+my $out = 'out';
+
+my @t =
+ (
+ # An empty test name signals that these are the arguments to use for the
+ # following tests.
+ ['', [qw (cbs=3 conv=unblock status=noxfer < )]],
+ ['0', '', ''],
+ ['1', "a\n ", "a\n\n\n"],
+ ['2', "a\n ", "a\n\n"],
+ ['3', "a ", "a\n"],
+ ['4', "a \n ", "a \n\n\n"],
+ ['5', "a \n", "a \n\n"],
+ ['6', "a ", "a\n\n"],
+ ['7', "a \n", "a\n\n\n"],
+ );
+
+my @Tests;
+my $args;
+foreach my $t (@t)
+ {
+ $t->[0] eq ''
+ and $args = $t->[1], next;
+
+ push @Tests, [$t->[0], @$args, {IN=>$t->[1]}, {OUT=>$t->[2]},
+ {ERR_SUBST=>'s/^\d+\+\d+ records (?:in|out)$//'},
+ {ERR=>"\n\n"}];
+ }
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $prog = 'dd';
+my $fail = run_tests ($program_name, $prog, \@Tests, $save_temps, $verbose);
+exit $fail;