aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/Makefile.am11
-rwxr-xr-xtests/cp/preserve-slink-time2
-rwxr-xr-xtests/dd/skip-seek-past-file3
-rwxr-xr-xtests/dd/unblock59
-rwxr-xr-xtests/id/no-context40
-rwxr-xr-xtests/ln/hard-to-sym82
-rwxr-xr-xtests/ln/misc23
-rwxr-xr-xtests/ln/slash-decorated-nonexistent-dest34
-rwxr-xr-xtests/ls/color-clear-to-eol6
-rwxr-xr-xtests/ls/color-dtype-dir20
-rwxr-xr-xtests/ls/dangle14
-rwxr-xr-xtests/ls/infloop25
-rwxr-xr-xtests/ls/stat-vs-dirent5
-rwxr-xr-xtests/misc/cat-buf15
-rwxr-xr-xtests/misc/ls-misc2
-rwxr-xr-xtests/misc/md5sum10
-rwxr-xr-xtests/misc/sha1sum11
-rwxr-xr-xtests/misc/sort-continue2
-rwxr-xr-xtests/misc/stat-hyphen35
-rwxr-xr-xtests/misc/stat-slash49
-rwxr-xr-xtests/misc/xattr42
-rwxr-xr-xtests/readlink/can-f36
-rwxr-xr-xtests/tail-2/append-only9
-rwxr-xr-xtests/tail-2/assert8
-rwxr-xr-xtests/tail-2/flush-initial44
-rwxr-xr-xtests/tail-2/follow-stdin41
-rwxr-xr-xtests/tail-2/infloop-112
-rwxr-xr-xtests/tail-2/pid47
-rwxr-xr-xtests/tail-2/pipe-f32
-rwxr-xr-xtests/tail-2/pipe-f237
-rwxr-xr-xtests/tail-2/tail-n0f24
-rwxr-xr-xtests/tail-2/wait67
-rwxr-xr-xtests/touch/60-seconds38
33 files changed, 741 insertions, 144 deletions
diff --git a/tests/Makefile.am b/tests/Makefile.am
index d9ff95be4..8dc90f9f2 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -216,7 +216,9 @@ TESTS = \
misc/split-fail \
misc/split-l \
misc/stat-fmt \
+ misc/stat-hyphen \
misc/stat-printf \
+ misc/stat-slash \
misc/stdbuf \
misc/stty \
misc/stty-invalid \
@@ -309,6 +311,7 @@ TESTS = \
dd/skip-seek2 \
dd/skip-seek-past-file \
dd/stderr \
+ dd/unblock \
dd/unblock-sync \
df/total-verify \
du/2g \
@@ -333,6 +336,7 @@ TESTS = \
du/slink \
du/trailing-slash \
du/two-args \
+ id/no-context \
install/basic-1 \
install/create-leading \
install/d-slashdot \
@@ -342,8 +346,10 @@ TESTS = \
install/trap \
ln/backup-1 \
ln/hard-backup \
+ ln/hard-to-sym \
ln/misc \
ln/sf-1 \
+ ln/slash-decorated-nonexistent-dest \
ln/target-1 \
ls/abmon-align \
ls/color-clear-to-eol \
@@ -427,8 +433,13 @@ TESTS = \
rmdir/t-slash \
tail-2/assert-2 \
tail-2/big-4gb \
+ tail-2/flush-initial \
+ tail-2/follow-stdin \
+ tail-2/pipe-f \
+ tail-2/pipe-f2 \
tail-2/proc-ksyms \
tail-2/start-middle \
+ touch/60-seconds \
touch/dangling-symlink \
touch/dir-1 \
touch/fail-diag \
diff --git a/tests/cp/preserve-slink-time b/tests/cp/preserve-slink-time
index c5c21a5e1..407b77272 100755
--- a/tests/cp/preserve-slink-time
+++ b/tests/cp/preserve-slink-time
@@ -24,6 +24,7 @@ fi
. $srcdir/test-lib.sh
grep '^#define HAVE_UTIMENSAT' "$CONFIG_HEADER" > /dev/null ||
+grep '^#define HAVE_LUTIMES' "$CONFIG_HEADER" > /dev/null ||
skip_test_ 'this system lacks the utimensat function'
ln -s no-such dangle || framework_failure
@@ -34,6 +35,7 @@ case $(stat --format=%y dangle) in
??:??:??.000000000) sleep 2;;
esac
+# Can't use --format=%x, as lstat() modifies atime on some platforms.
cp -Pp dangle d2 || framework_failure
stat --format=%y dangle > t1 || framework_failure
stat --format=%y d2 > t2 || framework_failure
diff --git a/tests/dd/skip-seek-past-file b/tests/dd/skip-seek-past-file
index cb36d08d9..937f99e17 100755
--- a/tests/dd/skip-seek-past-file
+++ b/tests/dd/skip-seek-past-file
@@ -22,7 +22,8 @@ if test "$VERBOSE" = yes; then
fi
. $srcdir/test-lib.sh
-eval $(getlimits) #for OFF_T limits
+require_sparse_support_ # for `truncate --size=$OFF_T_MAX`
+eval $(getlimits) # for OFF_T limits
fail=0
diff --git a/tests/dd/unblock b/tests/dd/unblock
new file mode 100755
index 000000000..6a3634cbb
--- /dev/null
+++ b/tests/dd/unblock
@@ -0,0 +1,59 @@
+#!/usr/bin/perl
+# Exercise dd's conv=unblock mode
+
+# Copyright (C) 2009 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 <http://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;
diff --git a/tests/id/no-context b/tests/id/no-context
new file mode 100755
index 000000000..f875ee0bc
--- /dev/null
+++ b/tests/id/no-context
@@ -0,0 +1,40 @@
+#!/bin/sh
+# With POSIXLY_CORRECT, id must not print context=...
+
+# Copyright (C) 2009 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 <http://www.gnu.org/licenses/>.
+
+if test "$VERBOSE" = yes; then
+ set -x
+ id --version
+fi
+
+. $srcdir/test-lib.sh
+
+# We don't need selinux *FS* support to test id,
+# but this is as good a witness as any, in general.
+require_selinux_
+
+fail=0
+
+# Require the context=... part by default.
+id > out || fail=1
+grep context= out || fail=1
+
+# Require no context=... part in conforming mode.
+POSIXLY_CORRECT=1 id > out || fail=1
+grep context= out && fail=1
+
+Exit $fail
diff --git a/tests/ln/hard-to-sym b/tests/ln/hard-to-sym
new file mode 100755
index 000000000..510b57abf
--- /dev/null
+++ b/tests/ln/hard-to-sym
@@ -0,0 +1,82 @@
+#!/bin/sh
+# Tests for ln -L/-P.
+
+# Copyright (C) 2009 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 <http://www.gnu.org/licenses/>.
+
+if test "$VERBOSE" = yes; then
+ set -x
+ ln --version
+fi
+
+. $srcdir/test-lib.sh
+
+fail=0
+
+# ===================================================
+# ensure -s silently overrides -L, -P
+touch a || framework_failure
+ln -L -s a symlink1 || fail=1
+ln -P -s symlink1 symlink2 || fail=1
+ln -s -L -P symlink2 symlink3 || fail=1
+
+# ===================================================
+# ensure that -L follows symlinks, and overrides -P
+ln -P -L symlink3 hard-to-a || fail=1
+ls=`ls -lG hard-to-a`x
+case "$ls" in
+ *'hard-to-ax') ;;
+ *'hard-to-a -> '*x) fail=1 ;;
+ *) framework_failure ;;
+esac
+
+# ===================================================
+# ensure that -P links (or at least duplicates) symlinks, and overrides -L
+ln -L -P symlink3 hard-to-3 || fail=1
+ls=`ls -lG hard-to-3`x
+case "$ls" in
+ *'hard-to-3 -> symlink2x') ;;
+ *'hard-to-3x') fail=1 ;;
+ *'hard-to-3 -> '*x) fail=1 ;;
+ *) framework_failure ;;
+esac
+
+# ===================================================
+# Create a hard link to a dangling symlink.
+ln -s /no-such-dir || framework_failure
+ln -L no-such-dir hard-to-dangle 2>err && fail=1
+case `cat err` in
+ *' accessing `no-such-dir'\':*) ;;
+ *) fail=1 ;;
+esac
+ln -P no-such-dir hard-to-dangle || fail=1
+
+# ===================================================
+# Create a hard link to a symlink to a directory.
+mkdir d || framework_failure
+ln -s d link-to-dir || framework_failure
+ln -L link-to-dir hard-to-dir-link 2>err && fail=1
+case `cat err` in
+ *': `link-to-dir'\'': hard link not allowed for directory'*) ;;
+ *) fail=1 ;;
+esac
+ln -P link-to-dir/ hard-to-dir-link 2>err && fail=1
+case `cat err` in
+ *': `link-to-dir/'\'': hard link not allowed for directory'*) ;;
+ *) fail=1 ;;
+esac
+ln -P link-to-dir hard-to-dir-link || fail=1
+
+Exit $fail
diff --git a/tests/ln/misc b/tests/ln/misc
index f13bd7bf3..d42d68a27 100755
--- a/tests/ln/misc
+++ b/tests/ln/misc
@@ -108,29 +108,6 @@ ln b b~ || framework_failure
ln -f --b=simple a b || fail=1
# ===================================================
-# determine if link(2) follows symlinks on this system
-touch a || framework_failure
-ln -s a symlink || framework_failure
-ln symlink hard-to-sym > /dev/null 2>&1 || framework_failure
-ls=`ls -lG hard-to-sym`x
-case "$ls" in
- *'hard-to-symx') link_follows_symlink=yes ;;
- *'hard-to-sym -> ax') link_follows_symlink=no ;;
- *) framework_failure ;;
-esac
-
-if test $link_follows_symlink = no; then
- # Create a hard link to a dangling symlink.
- # This is not portable. At least sunos4.1.4 and OpenBSD 2.3 fail this test.
- # They get this:
- # ln: cannot create hard link `hard-to-dangle' to `no-such-dir': \
- # No such file or directory
- #
- ln -s /no-such-dir || fail=1
- ln no-such-dir hard-to-dangle > /dev/null 2>&1 || fail=1
-fi
-rm -rf a symlink hard-to-sym hard-to-dangle
-# ===================================================
# Make sure ln can make simple backups.
# This was fixed in 4.0.34. Broken in 4.0r.
diff --git a/tests/ln/slash-decorated-nonexistent-dest b/tests/ln/slash-decorated-nonexistent-dest
new file mode 100755
index 000000000..afbbd060d
--- /dev/null
+++ b/tests/ln/slash-decorated-nonexistent-dest
@@ -0,0 +1,34 @@
+#!/bin/sh
+# ensure that touch f; ln -T f no-such-file/ does not mistakenly succeed
+
+# Copyright (C) 2009 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 <http://www.gnu.org/licenses/>.
+
+if test "$VERBOSE" = yes; then
+ set -x
+ ln --version
+fi
+
+. $srcdir/test-lib.sh
+
+touch f || framework_failure
+
+fail=0
+
+# Before coreutils-7.6, this would succeed on Solaris 10
+ln -T f no-such-file/ && fail=1
+test -e no-such-file && fail=1
+
+Exit $fail
diff --git a/tests/ls/color-clear-to-eol b/tests/ls/color-clear-to-eol
index 92cf8a8ca..fd65ced08 100755
--- a/tests/ls/color-clear-to-eol
+++ b/tests/ls/color-clear-to-eol
@@ -30,11 +30,15 @@ e='\33'
color_code='0;31;42'
c_pre="$e[0m$e[${color_code}m"
c_post="$e[0m$e[K\n$e[m"
-printf "$c_pre$long_name$c_post" > exp || framework_failure
+printf "$c_pre$long_name$c_post\n" > exp || framework_failure
fail=0
env TERM=xterm COLUMNS=80 LS_COLORS="*.foo=$color_code" TIME_STYLE=+T \
ls -og --color=always $long_name > out || fail=1
+
+# Append a newline, to accommodate less-capable versions of sed.
+echo >> out || fail=1
+
sed 's/.*T //' out > k && mv k out
compare out exp || fail=1
diff --git a/tests/ls/color-dtype-dir b/tests/ls/color-dtype-dir
index 5381a6684..3ccf10eb8 100755
--- a/tests/ls/color-dtype-dir
+++ b/tests/ls/color-dtype-dir
@@ -50,4 +50,24 @@ EOF
compare out exp || fail=1
+rm exp
+
+# Turn off colors for other-writable dirs and ensure
+# we fall back to the color for standard directories.
+
+LS_COLORS="ow=:" ls --color=always > out || fail=1
+cat -A out > o1 || fail=1
+echo >> o1 || fail=1
+mv o1 out || fail=1
+
+cat <<\EOF > exp || fail=1
+^[[0m^[[01;34md^[[0m$
+^[[01;34mother-writable^[[0m$
+out$
+^[[37;44msticky^[[0m$
+^[[m
+EOF
+
+compare out exp || fail=1
+
Exit $fail
diff --git a/tests/ls/dangle b/tests/ls/dangle
index b2f8539b8..687d3dfba 100755
--- a/tests/ls/dangle
+++ b/tests/ls/dangle
@@ -26,6 +26,10 @@ fi
ln -s no-such-file dangle || framework_failure
mkdir -p dir/sub || framework_failure
ln -s dir slink-to-dir || framework_failure
+mkdir d || framework_failure
+ln -s no-such d/dangle || framework_failure
+printf '? dangle\n' > subdir_Li_exp || framework_failure
+printf 'total 0\n? dangle\n' > subdir_Ls_exp || framework_failure
fail=0
@@ -50,4 +54,14 @@ EOF
compare out exp || fail=1
+# Ensure that ls -Li prints "?" as the inode of a dangling symlink.
+rm -f out
+ls -Li d > out 2>/dev/null && fail=1
+compare out subdir_Li_exp || fail=1
+
+# Ensure that ls -Ls prints "?" as the allocation of a dangling symlink.
+rm -f out
+ls -Ls d > out 2>/dev/null && fail=1
+compare out subdir_Ls_exp || fail=1
+
Exit $fail
diff --git a/tests/ls/infloop b/tests/ls/infloop
index 419d7a9f7..b77f88cdb 100755
--- a/tests/ls/infloop
+++ b/tests/ls/infloop
@@ -1,7 +1,7 @@
#!/bin/sh
# show that the following no longer makes ls infloop
# mkdir loop; cd loop; ln -s ../loop sub; ls -RL
-
+# Also ensure ls exits with status = 2 in that case.
# Copyright (C) 2001-2002, 2004, 2006-2009 Free Software Foundation, Inc.
# This program is free software: you can redistribute it and/or modify
@@ -27,21 +27,22 @@ fi
mkdir loop || framework_failure
ln -s ../loop loop/sub || framework_failure
-fail=0
-
-ls -RL loop 2>err | head -n 7 > out
-# With an inf-looping ls, out will contain these 7 lines:
-cat <<EOF > bad
+cat <<\EOF > exp-out || framework_failure
loop:
sub
+EOF
-loop/sub:
-sub
-
-loop/sub/sub:
+cat <<\EOF > exp-err || framework_failure
+ls: loop/sub: not listing already-listed directory
EOF
-# Make sure we don't get the "bad" output.
-compare out bad > /dev/null 2>&1 && fail=1
+fail=0
+
+timeout 1 ls -RL loop 2>err > out
+# Ensure that ls exits with status 2 upon detecting a cycle
+test $? = 2 || fail=1
+
+compare err exp-err || fail=1
+compare out exp-out || fail=1
Exit $fail
diff --git a/tests/ls/stat-vs-dirent b/tests/ls/stat-vs-dirent
index 064ec12ae..9f2b14925 100755
--- a/tests/ls/stat-vs-dirent
+++ b/tests/ls/stat-vs-dirent
@@ -43,7 +43,10 @@ while :; do
# Make sure that they are the same.
# We know from experience that there may be mismatches on some
# buggy file systems, at mount points.
- if test "$d_ino" != "$st_ino"; then
+ # Note that when a directory contains only entries whose names
+ # start with ".", d_ino and file will both be empty. In that case,
+ # skip the test.
+ if test -n "$d_ino" && test "$d_ino" != "$st_ino"; then
echo "$0: test failed: $t/$file: d_ino($d_ino) != st_ino($st_ino)
This may indicate a flaw in your kernel or file system implementation.
The flaw isn't serious for coreutils, but it might break other tools,
diff --git a/tests/misc/cat-buf b/tests/misc/cat-buf
index fb9ae881e..11d553a2b 100755
--- a/tests/misc/cat-buf
+++ b/tests/misc/cat-buf
@@ -30,12 +30,17 @@ fi
# write separately.
mkfifo fifo || framework_failure
-echo '1' > exp
+fail=0
-dd count=1 if=fifo > out 2> err&
-(echo '1'; sleep .2; echo '2') | cat -v > fifo
-wait #for dd to complete
+echo 1 > exp
-compare out exp || fail=1
+dd count=1 if=fifo > out &
+(echo 1; sleep .5; echo 2) | cat -v > fifo
+wait # for dd to complete
+
+# Though unlikely, this test may fail because dd was starved
+# between opening the fifo and reading from it until after the
+# second echo. So ask to double check rather than failing.
+compare out exp || skip_test_ "possible test failure. Please verify."
Exit $fail
diff --git a/tests/misc/ls-misc b/tests/misc/ls-misc
index 63810a559..a734d5fb9 100755
--- a/tests/misc/ls-misc
+++ b/tests/misc/ls-misc
@@ -239,6 +239,8 @@ my @Tests =
],
);
+umask 022;
+
# Start with an unset LS_COLORS environment variable.
delete $ENV{LS_COLORS};
diff --git a/tests/misc/md5sum b/tests/misc/md5sum
index 2fb024d16..30edd9e7f 100755
--- a/tests/misc/md5sum
+++ b/tests/misc/md5sum
@@ -67,6 +67,16 @@ my @Tests =
['check-bsd3', '--check', '--status',
{IN=> {'f.md5' => "MD5 (f) = $degenerate\n"}},
{AUX=> {f=> 'bar'}}, {EXIT=> 1}],
+ ['check-openssl', '--check', {IN=> {'f.sha1' => "SHA1(f)= $degenerate\n"}},
+ {AUX=> {f=> ''}},
+ {ERR=>"md5sum: f.sha1: no properly formatted "
+ . "MD5 checksum lines found\n"},
+ {EXIT=> 1}],
+ ['check-openssl2', '--check', {IN=> {'f.md5' => "MD5(f)= $degenerate\n"}},
+ {AUX=> {f=> ''}}, {OUT=>"f: OK\n"}],
+ ['check-openssl3', '--check', '--status',
+ {IN=> {'f.md5' => "MD5(f)= $degenerate\n"}},
+ {AUX=> {f=> 'bar'}}, {EXIT=> 1}],
['bsd-segv', '--check', {IN=> {'z' => "MD5 ("}}, {EXIT=> 1},
{ERR=> "$prog: z: no properly formatted MD5 checksum lines found\n"}],
diff --git a/tests/misc/sha1sum b/tests/misc/sha1sum
index 3f09abaae..d084204d0 100755
--- a/tests/misc/sha1sum
+++ b/tests/misc/sha1sum
@@ -60,6 +60,17 @@ my @Tests =
['check-bsd3', '--check', '--status',
{IN=> {'f.sha1' => "SHA1 (f) = $sha_degenerate\n"}},
{AUX=> {f=> 'bar'}}, {EXIT=> 1}],
+ ['check-openssl', '--check', {IN=> {'f.md5' => "MD5(f)= $sha_degenerate\n"}},
+ {AUX=> {f=> ''}},
+ {ERR=>"sha1sum: f.md5: no properly formatted "
+ . "SHA1 checksum lines found\n"},
+ {EXIT=> 1}],
+ ['check-openssl2', '--check',
+ {IN=> {'f.sha1' => "SHA1(f)= $sha_degenerate\n"}},
+ {AUX=> {f=> ''}}, {OUT=>"f: OK\n"}],
+ ['check-openssl3', '--check', '--status',
+ {IN=> {'f.sha1' => "SHA1(f)= $sha_degenerate\n"}},
+ {AUX=> {f=> 'bar'}}, {EXIT=> 1}],
['bsd-segv', '--check', {IN=> {'z' => "SHA1 ("}}, {EXIT=> 1},
{ERR=> "$prog: z: no properly formatted SHA1 checksum lines found\n"}],
);
diff --git a/tests/misc/sort-continue b/tests/misc/sort-continue
index 1b0ef431c..8b206f35c 100755
--- a/tests/misc/sort-continue
+++ b/tests/misc/sort-continue
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
# Tests for file descriptor exhaustion.
# Copyright (C) 2009 Free Software Foundation, Inc.
diff --git a/tests/misc/stat-hyphen b/tests/misc/stat-hyphen
new file mode 100755
index 000000000..f0757fe39
--- /dev/null
+++ b/tests/misc/stat-hyphen
@@ -0,0 +1,35 @@
+#!/bin/sh
+# demonstrate that stat - works and stat -f - does not.
+
+# Copyright (C) 2009 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 <http://www.gnu.org/licenses/>.
+
+if test "$VERBOSE" = yes; then
+ set -x
+ stat --version
+fi
+
+. $srcdir/test-lib.sh
+
+printf -- '-\n' > exp || framework_failure
+touch f || framework_failure
+
+fail=0
+stat --format=%n - < f > out || fail=1
+stat -f - < f && fail=1
+
+compare out exp || fail=1
+
+Exit $fail
diff --git a/tests/misc/stat-slash b/tests/misc/stat-slash
new file mode 100755
index 000000000..cda94c544
--- /dev/null
+++ b/tests/misc/stat-slash
@@ -0,0 +1,49 @@
+#!/bin/sh
+# demonstrate that stat handles trailing slashes correctly
+
+# Copyright (C) 2009 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 <http://www.gnu.org/licenses/>.
+
+if test "$VERBOSE" = yes; then
+ set -x
+ stat --version
+fi
+
+. $srcdir/test-lib.sh
+
+touch file || framework_failure
+mkdir dir || framework_failure
+ln -s file link1 || framework_failure
+ln -s dir link2 || framework_failure
+
+cat <<EOF > exp || framework_failure
+link1
+symbolic link
+directory
+directory
+EOF
+
+fail=0
+# This failed on Solaris 9 for coreutils 8.0.
+stat --format=%n link1 > out || fail=1
+stat --format=%n link1/ >> out && fail=1
+
+stat --format=%F link2 >> out || fail=1
+stat -L --format=%F link2 >> out || fail=1
+stat --format=%F link2/ >> out || fail=1
+
+compare out exp || fail=1
+
+Exit $fail
diff --git a/tests/misc/xattr b/tests/misc/xattr
index a27e1f6d9..fcf7ceb79 100755
--- a/tests/misc/xattr
+++ b/tests/misc/xattr
@@ -29,7 +29,7 @@ fi
# Skip this test if cp was built without xattr support:
touch src dest || framework_failure
-cp --preserve=xattr -n src dest 2>/dev/null \
+cp --preserve=xattr -n src dest \
|| skip_test_ "coreutils built without xattr support"
# this code was taken from test mv/backup-is-src
@@ -46,13 +46,13 @@ xattr_pair="$xattr_name=\"$xattr_value\""
# create new file and check its xattrs
touch a || framework_failure
getfattr -d a >out_a || skip_test_ "failed to get xattr of file"
-grep -F "$xattr_pair" out_a >/dev/null && framework_failure
+grep -F "$xattr_pair" out_a && framework_failure
# try to set user xattr on file
setfattr -n "$xattr_name" -v "$xattr_value" a >out_a \
|| skip_test_ "failed to set xattr of file"
getfattr -d a >out_a || skip_test_ "failed to get xattr of file"
-grep -F "$xattr_pair" out_a >/dev/null \
+grep -F "$xattr_pair" out_a \
|| skip_test_ "failed to set xattr of file"
fail=0
@@ -60,36 +60,50 @@ fail=0
# cp should not preserve xattr by default
cp a b || fail=1
getfattr -d b >out_b || skip_test_ "failed to get xattr of file"
-grep -F "$xattr_pair" out_b >/dev/null && fail=1
+grep -F "$xattr_pair" out_b && fail=1
# test if --preserve=xattr option works
cp --preserve=xattr a b || fail=1
getfattr -d b >out_b || skip_test_ "failed to get xattr of file"
-grep -F "$xattr_pair" out_b >/dev/null || fail=1
+grep -F "$xattr_pair" out_b || fail=1
#test if --preserve=all option works
cp --preserve=all a c || fail=1
getfattr -d c >out_c || skip_test_ "failed to get xattr of file"
-grep -F "$xattr_pair" out_c >/dev/null || fail=1
+grep -F "$xattr_pair" out_c || fail=1
#test if -a option works without any diagnostics
cp -a a d 2>err && test -s err && fail=1
getfattr -d d >out_d || skip_test_ "failed to get xattr of file"
-grep -F "$xattr_pair" out_d >/dev/null || fail=1
+grep -F "$xattr_pair" out_d || fail=1
+
+#test if --preserve=xattr works even for files without write access
+chmod a-w a || framework_failure
+rm -f e
+cp --preserve=xattr a e || fail=1
+getfattr -d e >out_e || skip_test_ "failed to get xattr of file"
+grep -F "$xattr_pair" out_e || fail=1
+
+#Ensure that permission bits are preserved, too.
+src_perm=$(stat --format=%a a)
+dst_perm=$(stat --format=%a e)
+test "$dst_perm" = "$src_perm" || fail=1
+
+chmod u+w a || framework_failure
rm b || framework_failure
# install should never preserve xattr
ginstall a b || fail=1
getfattr -d b >out_b || skip_test_ "failed to get xattr of file"
-grep -F "$xattr_pair" out_b >/dev/null && fail=1
+grep -F "$xattr_pair" out_b && fail=1
# mv should preserve xattr when renaming within a file system.
# This is implicitly done by rename () and doesn't need explicit
# xattr support in mv.
mv a b || fail=1
getfattr -d b >out_b || skip_test_ "failed to get xattr of file"
-grep -F "$xattr_pair" out_b >/dev/null || cat >&2 <<EOF
+grep -F "$xattr_pair" out_b || cat >&2 <<EOF
=================================================================
$0: WARNING!!!
rename () does not preserve extended attributes
@@ -99,18 +113,18 @@ EOF
# try to set user xattr on file on other partition
test_mv=1
touch "$b_other" || framework_failure
-setfattr -n "$xattr_name" -v "$xattr_value" "$b_other" >out_a 2>/dev/null \
+setfattr -n "$xattr_name" -v "$xattr_value" "$b_other" >out_a \
|| test_mv=0
-getfattr -d "$b_other" >out_b 2>/dev/null || test_mv=0
-grep -F "$xattr_pair" out_b >/dev/null || test_mv=0
+getfattr -d "$b_other" >out_b || test_mv=0
+grep -F "$xattr_pair" out_b || test_mv=0
rm -f "$b_other" || framework_failure
if test $test_mv -eq 1; then
# mv should preserve xattr when copying content from one partition to another
mv b "$b_other" || fail=1
- getfattr -d "$b_other" >out_b 2>/dev/null ||
+ getfattr -d "$b_other" >out_b ||
skip_test_ "failed to get xattr of file"
- grep -F "$xattr_pair" out_b >/dev/null || fail=1
+ grep -F "$xattr_pair" out_b || fail=1
else
cat >&2 <<EOF
=================================================================
diff --git a/tests/readlink/can-f b/tests/readlink/can-f
index 8a000f8e9..a702ba990 100755
--- a/tests/readlink/can-f
+++ b/tests/readlink/can-f
@@ -38,6 +38,7 @@ ln -s regfile link1 || framework_failure
ln -s subdir link2 || framework_failure
ln -s missing link3 || framework_failure
ln -s subdir/missing link4 || framework_failure
+ln -s link5 link5 || framework_failure
cd "$pwd/$tmp/removed" || framework_failure
@@ -73,14 +74,14 @@ for p in "" "$pwd/$tmp/"; do
v=`readlink -f "${p}subdir/more"` || fail=1
test "$v" = "$my_pwd/$tmp/subdir/more" || fail=1
- v=`readlink -f "${p}./subdir/more/"` && fail=1
- test -z "$v" || fail=1
+ v=`readlink -f "${p}./subdir/more/"` || fail=1
+ test "$v" = "$my_pwd/$tmp/subdir/more" || fail=1
v=`readlink -f "${p}missing"` || fail=1
test "$v" = "$my_pwd/$tmp/missing" || fail=1
- v=`readlink -f "${p}./missing/"` && fail=1
- test -z "$v" || fail=1
+ v=`readlink -f "${p}./missing/"` || fail=1
+ test "$v" = "$my_pwd/$tmp/missing" || fail=1
v=`readlink -f "${p}missing/more"` && fail=1
test -z "$v" || fail=1
@@ -109,8 +110,8 @@ for p in "" "$pwd/$tmp/"; do
v=`readlink -f "${p}link2/more"` || fail=1
test "$v" = "$my_pwd/$tmp/subdir/more" || fail=1
- v=`readlink -f "${p}./link2/more/"` && fail=1
- test -z "$v" || fail=1
+ v=`readlink -f "${p}./link2/more/"` || fail=1
+ test "$v" = "$my_pwd/$tmp/subdir/more" || fail=1
v=`readlink -f "${p}link2/more/more2"` && fail=1
test -z "$v" || fail=1
@@ -121,8 +122,8 @@ for p in "" "$pwd/$tmp/"; do
v=`readlink -f "${p}link3"` || fail=1
test "$v" = "$my_pwd/$tmp/missing" || fail=1
- v=`readlink -f "${p}./link3/"` && fail=1
- test -z "$v" || fail=1
+ v=`readlink -f "${p}./link3/"` || fail=1
+ test "$v" = "$my_pwd/$tmp/missing" || fail=1
v=`readlink -f "${p}link3/more"` && fail=1
test -z "$v" || fail=1
@@ -133,11 +134,26 @@ for p in "" "$pwd/$tmp/"; do
v=`readlink -f "${p}link4"` || fail=1
test "$v" = "$my_pwd/$tmp/subdir/missing" || fail=1
- v=`readlink -f "${p}./link4/"` && fail=1
- test -z "$v" || fail=1
+ v=`readlink -f "${p}./link4/"` || fail=1
+ test "$v" = "$my_pwd/$tmp/subdir/missing" || fail=1
v=`readlink -f "${p}link4/more"` && fail=1
test -z "$v" || fail=1
+
+ v=`readlink -f "${p}./link4/more"` && fail=1
+ test -z "$v" || fail=1
+
+ v=`readlink -f "${p}link5"` && fail=1
+ test -z "$v" || fail=1
+
+ v=`readlink -f "${p}./link5/"` && fail=1
+ test -z "$v" || fail=1
+
+ v=`readlink -f "${p}link5/more"` && fail=1
+ test -z "$v" || fail=1
+
+ v=`readlink -f "${p}./link5/more"` && fail=1
+ test -z "$v" || fail=1
done
Exit $fail
diff --git a/tests/tail-2/append-only b/tests/tail-2/append-only
index 0b4a95958..2d38d4f0f 100755
--- a/tests/tail-2/append-only
+++ b/tests/tail-2/append-only
@@ -37,9 +37,12 @@ fi
fail=0
-sleep 1 &
-pid=$!
-tail --pid=$pid -f f || fail=1
+for inotify in ---disable-inotify ''; do
+ sleep 1 &
+ pid=$!
+ tail --pid=$pid -f $inotify f || fail=1
+done
+
chattr -a f 2>/dev/null
Exit $fail
diff --git a/tests/tail-2/assert b/tests/tail-2/assert
index 623c3684f..416f206a1 100755
--- a/tests/tail-2/assert
+++ b/tests/tail-2/assert
@@ -42,13 +42,9 @@ tail_pid=$!
echo sleeping for 7 seconds...
-# Wait for the backgrounded `tail' to start before removing foo.
+# Give the backgrounded `tail' a chance to start before removing foo.
# Otherwise, without --retry, tail wouldn't try to open `foo' again.
-while :; do
- env kill -0 $tail_pid && break
- echo sleep .1
- sleep .1
-done
+sleep 1
rm -f foo
sleep 6
diff --git a/tests/tail-2/flush-initial b/tests/tail-2/flush-initial
new file mode 100755
index 000000000..e0d79fe48
--- /dev/null
+++ b/tests/tail-2/flush-initial
@@ -0,0 +1,44 @@
+#!/bin/sh
+# inotify-based tail -f didn't flush its initial output before blocking
+
+# Copyright (C) 2009 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 <http://www.gnu.org/licenses/>.
+
+if test "$VERBOSE" = yes; then
+ set -x
+ tail --version
+fi
+
+. $srcdir/test-lib.sh
+
+fail=0
+echo line > in || fail=1
+# Output should be buffered since we're writing to file
+# so we're depending on the flush to write out
+tail -f in > out &
+tail_pid=$!
+
+# Wait for 1 second for the file to be flushed.
+for i in $(seq 10); do
+ test -s out && break
+ echo sleep .1s
+ sleep .1
+done
+
+test -s out || fail=1
+
+kill $tail_pid
+
+Exit $fail
diff --git a/tests/tail-2/follow-stdin b/tests/tail-2/follow-stdin
new file mode 100755
index 000000000..46e7ce80f
--- /dev/null
+++ b/tests/tail-2/follow-stdin
@@ -0,0 +1,41 @@
+#!/bin/sh
+# tail -f - would fail with the initial inotify implementation
+
+# Copyright (C) 2009 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 <http://www.gnu.org/licenses/>.
+
+if test "$VERBOSE" = yes; then
+ set -x
+ tail --version
+fi
+
+. $srcdir/test-lib.sh
+
+echo line > exp || framework_failure
+echo line > in || framework_failure
+
+fail=0
+timeout 1 tail -f < in > out 2> err
+
+# tail from coreutils-7.5 would fail
+test $? = 124 || fail=1
+
+# Ensure there was no error output.
+test -s err && fail=1
+
+# Ensure there was
+compare out exp || fail=1
+
+Exit $fail
diff --git a/tests/tail-2/infloop-1 b/tests/tail-2/infloop-1
index 6a456deac..72d51d975 100755
--- a/tests/tail-2/infloop-1
+++ b/tests/tail-2/infloop-1
@@ -27,16 +27,22 @@ yes > t &
yes_pid=$!
while :; do
test -s t && break
+ sleep .1
done
tail -n 1 t &
tail_pid=$!
kill $yes_pid
# This test is racy, and can fail under unusual circumstances.
-# On a busy system, "yes" will fail to write
-# (and hence fail to be killed by SIGPIPE) in that 1-second interval.
+# On a very busy system, tail will fail to notice that $yes_pid is gone.
# Then the following kill will succeed and cause this test to fail.
-sleep 1
+
+# Wait for up to 3 seconds for tail to detect the death of $yes_pid.
+for i in $(seq 30); do
+ kill -0 $tail_pid || break
+ echo sleep 0.1s
+ sleep .1
+done
fail=0
kill $tail_pid && fail=1 || :
diff --git a/tests/tail-2/pid b/tests/tail-2/pid
index a797666fe..760e289bc 100755
--- a/tests/tail-2/pid
+++ b/tests/tail-2/pid
@@ -22,32 +22,35 @@ if test "$VERBOSE" = yes; then
fi
. $srcdir/test-lib.sh
+getlimits_
touch here || framework_failure
fail=0
-# Use tail itself to create a background process to monitor.
-tail -f here &
-bg_pid=$!
-
-# Ensure that tail --pid=PID does not exit when PID is alive.
-timeout 1 tail -s.1 -f here --pid=$bg_pid
-test $? = 124 || fail=1
-
-# Cleanup background process
-kill $bg_pid
-
-# Ensure that tail --pid=PID exits successfully when PID is dead.
-# Use an unlikely-to-be-live PID
-getlimits_
-timeout 1 tail -s.1 --pid=$PID_T_MAX -f /dev/null
-ret=$?
-test $ret = 124 && skip_test_ "pid $PID_T_MAX present"
-test $ret = 0 || fail=1
-
-# Ensure fractional sleep parameter is honored with --pid
-timeout 1 tail -s.1 -f /dev/null --pid=$PID_T_MAX
-test $? = 124 && fail=1
+for inotify in ---disable-inotify ''; do
+ # Use tail itself to create a background process to monitor,
+ # which will auto exit when "here" is removed.
+ tail -f $inotify here &
+ bg_pid=$!
+
+ # Ensure that tail --pid=PID does not exit when PID is alive.
+ timeout 1 tail -f -s.1 --pid=$bg_pid $inotify here
+ test $? = 124 || fail=1
+
+ # Cleanup background process
+ kill $bg_pid
+
+ # Ensure that tail --pid=PID exits with success status when PID is dead.
+ # Use an unlikely-to-be-live PID
+ timeout 3 tail -f -s.1 --pid=$PID_T_MAX $inotify /dev/null
+ ret=$?
+ test $ret = 124 && skip_test_ "pid $PID_T_MAX present or tail too slow"
+ test $ret = 0 || fail=1
+
+ # Ensure tail doesn't wait for data when PID is dead
+ timeout 3 tail -f -s10 --pid=$PID_T_MAX $inotify /dev/null
+ test $? = 124 && fail=1
+done
Exit $fail
diff --git a/tests/tail-2/pipe-f b/tests/tail-2/pipe-f
new file mode 100755
index 000000000..b9f6ae389
--- /dev/null
+++ b/tests/tail-2/pipe-f
@@ -0,0 +1,32 @@
+#!/bin/sh
+# ensure that :|tail -f doesn't hang, per POSIX
+
+# Copyright (C) 2009 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 <http://www.gnu.org/licenses/>.
+
+if test "$VERBOSE" = yes; then
+ set -x
+ tail --version
+fi
+
+. $srcdir/test-lib.sh
+
+fail=0
+echo foo | timeout 2 tail -f -c3 > out || fail=1
+echo oo > exp || fail=1
+
+compare out exp || fail=1
+
+Exit $fail
diff --git a/tests/tail-2/pipe-f2 b/tests/tail-2/pipe-f2
new file mode 100755
index 000000000..406ebcc91
--- /dev/null
+++ b/tests/tail-2/pipe-f2
@@ -0,0 +1,37 @@
+#!/bin/sh
+# Ensure that "tail -f fifo" tails indefinitely.
+
+# Copyright (C) 2009 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 <http://www.gnu.org/licenses/>.
+
+if test "$VERBOSE" = yes; then
+ set -x
+ tail --version
+fi
+
+. $srcdir/test-lib.sh
+
+mkfifo_or_skip_ fifo
+
+echo 1 > fifo &
+echo 1 > exp || framework_failure
+
+fail=0
+timeout 1 tail -f fifo > out
+test $? = 124 || fail=1
+
+compare out exp || fail=1
+
+Exit $fail
diff --git a/tests/tail-2/tail-n0f b/tests/tail-2/tail-n0f
index fce7ed16e..ddfbe6645 100755
--- a/tests/tail-2/tail-n0f
+++ b/tests/tail-2/tail-n0f
@@ -35,17 +35,19 @@ echo anything > nonempty || framework_failure
fail=0
-for file in empty nonempty; do
- for c_or_n in c n; do
- tail --sleep=4 -${c_or_n} 0 -f $file &
- pid=$!
- sleep .5
- state=$(get_process_status_ $pid)
- case $state in
- S*) ;;
- *) echo $0: process in unexpected state: $state 1>&2; fail=1 ;;
- esac
- kill $pid
+for inotify in ---disable-inotify ''; do
+ for file in empty nonempty; do
+ for c_or_n in c n; do
+ tail --sleep=4 -${c_or_n} 0 -f $inotify $file &
+ pid=$!
+ sleep .5
+ state=$(get_process_status_ $pid)
+ case $state in
+ S*) ;;
+ *) echo $0: process in unexpected state: $state 1>&2; fail=1 ;;
+ esac
+ kill $pid
+ done
done
done
diff --git a/tests/tail-2/wait b/tests/tail-2/wait
index a5f189fe0..62498d5dc 100755
--- a/tests/tail-2/wait
+++ b/tests/tail-2/wait
@@ -30,43 +30,48 @@ touch k || framework_failure
fail=0
-timeout 1 tail -s0.1 -f not_here
-test $? = 124 && fail=1
-
-if test ! -r unreadable; then # can't test this when root
- timeout 1 tail -s0.1 -f unreadable
+for inotify in ---disable-inotify ''; do
+ timeout 1 tail -s0.1 -f $inotify not_here
test $? = 124 && fail=1
-fi
-timeout 1 tail -s0.1 -f here 2>tail.err
-test $? = 124 || fail=1
+ if test ! -r unreadable; then # can't test this when root
+ timeout 1 tail -s0.1 -f $inotify unreadable
+ test $? = 124 && fail=1
+ fi
-# `tail -F' must wait in any case.
+ timeout 1 tail -s0.1 -f $inotify here 2>tail.err
+ test $? = 124 || fail=1
-timeout 1 tail -s0.1 -F here 2>>tail.err
-test $? = 124 || fail=1
+ # `tail -F' must wait in any case.
-if test ! -r unreadable; then # can't test this when root
- timeout 1 tail -s0.1 -F unreadable
+ timeout 1 tail -s0.1 -F $inotify here 2>>tail.err
test $? = 124 || fail=1
-fi
-timeout 1 tail -s0.1 -F not_here
-test $? = 124 || fail=1
-
-test -s tail.err && fail=1
-
-tail -s.1 --max-unchanged-stats=2 -F k > tail.out &
-pid=$!
-sleep .5
-mv k l
-sleep .5
-touch k
-mv k l
-sleep .5
-echo NO >> l
-sleep .5
-kill $pid
-test -s tail.out && fail=1
+ if test ! -r unreadable; then # can't test this when root
+ timeout 1 tail -s0.1 -F $inotify unreadable
+ test $? = 124 || fail=1
+ fi
+
+ timeout 1 tail -s0.1 -F $inotify not_here
+ test $? = 124 || fail=1
+
+
+ test -s tail.err && fail=1
+ :>tail.err
+
+
+ tail -s.1 --max-unchanged-stats=2 -F $inotify k > tail.out &
+ pid=$!
+ sleep .5
+ mv k l
+ sleep .5
+ touch k
+ mv k l
+ sleep .5
+ echo NO >> l
+ sleep .5
+ kill $pid
+ test -s tail.out && fail=1
+done
Exit $fail
diff --git a/tests/touch/60-seconds b/tests/touch/60-seconds
new file mode 100755
index 000000000..b13ad06ff
--- /dev/null
+++ b/tests/touch/60-seconds
@@ -0,0 +1,38 @@
+#!/bin/sh
+# touch -t would mistakenly reject a time specifying "60" seconds
+
+# Copyright (C) 2009 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 <http://www.gnu.org/licenses/>.
+
+if test "$VERBOSE" = yes; then
+ set -x
+ touch --version
+fi
+
+. $srcdir/test-lib.sh
+
+echo 60 > exp || framework_failure
+
+fail=0
+
+# Before coreutils-7.7, this would fail, complaining of
+# an `invalid date format'. Specifying 60 seconds *is* valid.
+TZ=UTC0 touch -t 197001010000.60 f || fail=1
+
+stat --p='%Y\n' f > out || fail=1
+
+compare out exp || fail=1
+
+Exit $fail