1#!/bin/sh
2# make sure that dd doesn't allocate memory unnecessarily
3
4# Copyright (C) 2013-2023 Free Software Foundation, Inc.
5
6# This program is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation, either version 3 of the License, or
9# (at your option) any later version.
10
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14# GNU General Public License for more details.
15
16# You should have received a copy of the GNU General Public License
17# along with this program.  If not, see <https://www.gnu.org/licenses/>.
18
19. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
20print_ver_ dd
21
22# Determine basic amount of memory needed.
23echo . > f || framework_failure_
24vm=$(get_min_ulimit_v_ timeout 10 dd if=f of=f2 status=none) \
25  || skip_ "this shell lacks ulimit support"
26rm f f2 || framework_failure_
27
28# count and skip are zero, we don't need to allocate memory
29(ulimit -v $vm && dd  bs=30M count=0) || fail=1
30(ulimit -v $vm && dd ibs=30M count=0) || fail=1
31(ulimit -v $vm && dd obs=30M count=0) || fail=1
32
33check_dd_seek_alloc() {
34  local file="$1"
35  local buf="$2"
36  test "$file" = 'in' && { dd_file=if; dd_op=skip; }
37  test "$file" = 'out' && { dd_file=of; dd_op=seek; }
38  test "$buf" = 'in' && { dd_buf=ibs; }
39  test "$buf" = 'out' && { dd_buf=obs; }
40  test "$buf" = 'both' && { dd_buf=bs; }
41
42  # Provide input to the "tape"
43  timeout 10 dd count=1 if=/dev/zero of=tape&
44
45  # Allocate buffer and read from the "tape"
46  (ulimit -v $vm \
47     && timeout 10 dd $dd_buf=30M $dd_op=1 count=0 $dd_file=tape)
48  local ret=$?
49
50  # Be defensive in case the tape reader is blocked for some reason
51  test $ret = 124 && framework_failure_
52
53  # This should happen without delay,
54  # and is used to ensure we've not multiple writers to the "tape"
55  wait
56
57  # We want the "tape" reader to fail iff allocating
58  # a large buffer corresponding to the file being read
59  case "$file$buf" in
60    inout|outin) test $ret = 0;;
61    *) test $ret != 0;;
62  esac
63}
64
65# Use a fifo for which seek fails, but read does not.
66# For non seekable output we need to allocate a buffer
67# when simulating seeking with a read.
68if mkfifo tape; then
69  for file in 'in' 'out'; do
70    for buf in 'both' 'in' 'out'; do
71      check_dd_seek_alloc "$file" "$buf" || fail=1
72    done
73  done
74fi
75
76Exit $fail
77