summaryrefslogtreecommitdiffstats
path: root/tests/ls
diff options
context:
space:
mode:
Diffstat (limited to 'tests/ls')
-rwxr-xr-xtests/ls/a-option.sh27
-rwxr-xr-xtests/ls/abmon-align.sh53
-rwxr-xr-xtests/ls/birthtime.sh27
-rwxr-xr-xtests/ls/block-size.sh186
-rwxr-xr-xtests/ls/capability.sh63
-rwxr-xr-xtests/ls/classify.sh63
-rwxr-xr-xtests/ls/color-clear-to-eol.sh41
-rwxr-xr-xtests/ls/color-dtype-dir.sh64
-rwxr-xr-xtests/ls/color-ext.sh41
-rwxr-xr-xtests/ls/color-norm.sh84
-rwxr-xr-xtests/ls/color-term.sh48
-rwxr-xr-xtests/ls/dangle.sh64
-rwxr-xr-xtests/ls/dired.sh35
-rwxr-xr-xtests/ls/file-type.sh65
-rwxr-xr-xtests/ls/follow-slink.sh63
-rwxr-xr-xtests/ls/getxattr-speedup.sh66
-rwxr-xr-xtests/ls/group-dirs.sh43
-rwxr-xr-xtests/ls/hex-option.sh24
-rwxr-xr-xtests/ls/hyperlink.sh63
-rwxr-xr-xtests/ls/infloop.sh41
-rwxr-xr-xtests/ls/inode.sh65
-rwxr-xr-xtests/ls/m-option.sh40
-rwxr-xr-xtests/ls/multihardlink.sh80
-rwxr-xr-xtests/ls/nameless-uid.sh40
-rwxr-xr-xtests/ls/no-arg.sh56
-rwxr-xr-xtests/ls/no-cap.sh33
-rwxr-xr-xtests/ls/quote-align.sh62
-rwxr-xr-xtests/ls/readdir-mountpoint-inode.sh73
-rwxr-xr-xtests/ls/recursive.sh62
-rwxr-xr-xtests/ls/removed-directory.sh38
-rwxr-xr-xtests/ls/root-rel-symlink-color.sh51
-rwxr-xr-xtests/ls/rt-1.sh46
-rwxr-xr-xtests/ls/selinux-segfault.sh33
-rwxr-xr-xtests/ls/slink-acl.sh33
-rwxr-xr-xtests/ls/sort-width-option.sh41
-rwxr-xr-xtests/ls/stat-dtype.sh60
-rwxr-xr-xtests/ls/stat-failed.sh57
-rwxr-xr-xtests/ls/stat-free-color.sh88
-rwxr-xr-xtests/ls/stat-free-symlinks.sh75
-rwxr-xr-xtests/ls/stat-vs-dirent.sh60
-rwxr-xr-xtests/ls/symlink-quote.sh30
-rwxr-xr-xtests/ls/symlink-slash.sh30
-rwxr-xr-xtests/ls/time-style-diag.sh38
-rwxr-xr-xtests/ls/w-option.sh48
-rwxr-xr-xtests/ls/x-option.sh37
-rwxr-xr-xtests/ls/zero-option.sh41
46 files changed, 2478 insertions, 0 deletions
diff --git a/tests/ls/a-option.sh b/tests/ls/a-option.sh
new file mode 100755
index 0000000..0c85e0b
--- /dev/null
+++ b/tests/ls/a-option.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+# exercise the -a option
+
+# Copyright 2018-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_ ls
+
+mkdir d || framework_failure_
+
+ls -aA d >out || framework_failure_
+compare /dev/null out || fail=1
+
+Exit $fail
diff --git a/tests/ls/abmon-align.sh b/tests/ls/abmon-align.sh
new file mode 100755
index 0000000..0ad5f3a
--- /dev/null
+++ b/tests/ls/abmon-align.sh
@@ -0,0 +1,53 @@
+#!/bin/sh
+# Ensure ls output is aligned when using abbreviated months from the locale
+
+# 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_ ls
+
+mid_month="$(date +%Y-%m-15)" || framework_failure_
+for mon in $(seq -w 12); do
+ touch -d"$mid_month +$mon month" $mon.ts || framework_failure_
+done
+
+
+# Note some of the following locales may be missing but if so
+# we should fail back to the C locale which should be aligned
+
+for format in "%b" "[%b" "%b]" "[%b]"; do
+ for LOC in C gv_GB ga_IE fi_FI.utf8 zh_CN ar_SY $LOCALE_FR_UTF8; do
+ # The sed usage here is slightly different from the original,
+ # removing the \(.*\), to avoid triggering misbehavior in at least
+ # GNU sed 4.2 (possibly miscompiled) on Mac OS X (Darwin 9.8.0).
+ months="$(
+ LC_ALL=$LOC TIME_STYLE=+"$format" ls -lgG *.ts |
+ LC_ALL=C sed 's/.\{15\}//;s/ ..\.ts$//;s/ /./g')"
+ n_widths=$(echo "$months" |
+ while read mon; do echo "$mon" | LC_ALL=$LOC wc -L; done |
+ uniq | wc -l
+ )
+ n_dupes=$(echo "$months" | sort | uniq -d | wc -l)
+ test "$n_widths" = "1" || { fail=1; break 2; }
+ test "$n_dupes" = "0" || { fail=1; break 2; }
+ done
+done
+if test "$fail" = "1"; then
+ echo "misalignment or ambiguous output in $LOC locale:"
+ LC_ALL=$LOC TIME_STYLE=+%b ls -lgG *.ts
+fi
+
+Exit $fail
diff --git a/tests/ls/birthtime.sh b/tests/ls/birthtime.sh
new file mode 100755
index 0000000..ddb5653
--- /dev/null
+++ b/tests/ls/birthtime.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+# ensure that ls attempts birthtime access
+
+# Copyright (C) 2020-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_ ls
+
+# ls should not fail, even if birth time not available
+touch a || framework_failure_
+ls --time=birth -l a || fail=1
+ls --time=creation -t a || fail=1
+
+Exit $fail
diff --git a/tests/ls/block-size.sh b/tests/ls/block-size.sh
new file mode 100755
index 0000000..7485e5e
--- /dev/null
+++ b/tests/ls/block-size.sh
@@ -0,0 +1,186 @@
+#!/bin/sh
+# Exercise ls --block-size and related options.
+
+# 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_ ls
+
+TZ=UTC0
+export TZ
+
+mkdir sub
+cd sub
+
+for size in 1024 4096 262144; do
+ echo foo | dd conv=sync bs=$size >file$size || fail=1
+done
+touch -d '2001-01-01 00:00' file* || fail=1
+
+size_etc='s/[^ ]* *[^ ]* *//'
+
+ls -og * | sed "$size_etc" >../out || fail=1
+POSIXLY_CORRECT=1 ls -og * | sed "$size_etc" >>../out || fail=1
+POSIXLY_CORRECT=1 ls -k -og * | sed "$size_etc" >>../out || fail=1
+
+for var in BLOCKSIZE BLOCK_SIZE LS_BLOCK_SIZE; do
+ for blocksize in 1 512 1K 1KiB; do
+ (eval $var=$blocksize && export $var &&
+ echo "x x # $var=$blocksize" &&
+ ls -og * &&
+ ls -og -k * &&
+ ls -og -k --block-size=$blocksize *
+ ) | sed "$size_etc" >>../out || fail=1
+ done
+done
+
+cd ..
+
+cat >exp <<'EOF'
+1024 Jan 1 2001 file1024
+262144 Jan 1 2001 file262144
+4096 Jan 1 2001 file4096
+1024 Jan 1 2001 file1024
+262144 Jan 1 2001 file262144
+4096 Jan 1 2001 file4096
+1024 Jan 1 2001 file1024
+262144 Jan 1 2001 file262144
+4096 Jan 1 2001 file4096
+# BLOCKSIZE=1
+1024 Jan 1 2001 file1024
+262144 Jan 1 2001 file262144
+4096 Jan 1 2001 file4096
+1024 Jan 1 2001 file1024
+262144 Jan 1 2001 file262144
+4096 Jan 1 2001 file4096
+1024 Jan 1 2001 file1024
+262144 Jan 1 2001 file262144
+4096 Jan 1 2001 file4096
+# BLOCKSIZE=512
+1024 Jan 1 2001 file1024
+262144 Jan 1 2001 file262144
+4096 Jan 1 2001 file4096
+1024 Jan 1 2001 file1024
+262144 Jan 1 2001 file262144
+4096 Jan 1 2001 file4096
+2 Jan 1 2001 file1024
+512 Jan 1 2001 file262144
+8 Jan 1 2001 file4096
+# BLOCKSIZE=1K
+1024 Jan 1 2001 file1024
+262144 Jan 1 2001 file262144
+4096 Jan 1 2001 file4096
+1024 Jan 1 2001 file1024
+262144 Jan 1 2001 file262144
+4096 Jan 1 2001 file4096
+1 Jan 1 2001 file1024
+256 Jan 1 2001 file262144
+4 Jan 1 2001 file4096
+# BLOCKSIZE=1KiB
+1024 Jan 1 2001 file1024
+262144 Jan 1 2001 file262144
+4096 Jan 1 2001 file4096
+1024 Jan 1 2001 file1024
+262144 Jan 1 2001 file262144
+4096 Jan 1 2001 file4096
+1 Jan 1 2001 file1024
+256 Jan 1 2001 file262144
+4 Jan 1 2001 file4096
+# BLOCK_SIZE=1
+1024 Jan 1 2001 file1024
+262144 Jan 1 2001 file262144
+4096 Jan 1 2001 file4096
+1024 Jan 1 2001 file1024
+262144 Jan 1 2001 file262144
+4096 Jan 1 2001 file4096
+1024 Jan 1 2001 file1024
+262144 Jan 1 2001 file262144
+4096 Jan 1 2001 file4096
+# BLOCK_SIZE=512
+2 Jan 1 2001 file1024
+512 Jan 1 2001 file262144
+8 Jan 1 2001 file4096
+2 Jan 1 2001 file1024
+512 Jan 1 2001 file262144
+8 Jan 1 2001 file4096
+2 Jan 1 2001 file1024
+512 Jan 1 2001 file262144
+8 Jan 1 2001 file4096
+# BLOCK_SIZE=1K
+1 Jan 1 2001 file1024
+256 Jan 1 2001 file262144
+4 Jan 1 2001 file4096
+1 Jan 1 2001 file1024
+256 Jan 1 2001 file262144
+4 Jan 1 2001 file4096
+1 Jan 1 2001 file1024
+256 Jan 1 2001 file262144
+4 Jan 1 2001 file4096
+# BLOCK_SIZE=1KiB
+1 Jan 1 2001 file1024
+256 Jan 1 2001 file262144
+4 Jan 1 2001 file4096
+1 Jan 1 2001 file1024
+256 Jan 1 2001 file262144
+4 Jan 1 2001 file4096
+1 Jan 1 2001 file1024
+256 Jan 1 2001 file262144
+4 Jan 1 2001 file4096
+# LS_BLOCK_SIZE=1
+1024 Jan 1 2001 file1024
+262144 Jan 1 2001 file262144
+4096 Jan 1 2001 file4096
+1024 Jan 1 2001 file1024
+262144 Jan 1 2001 file262144
+4096 Jan 1 2001 file4096
+1024 Jan 1 2001 file1024
+262144 Jan 1 2001 file262144
+4096 Jan 1 2001 file4096
+# LS_BLOCK_SIZE=512
+2 Jan 1 2001 file1024
+512 Jan 1 2001 file262144
+8 Jan 1 2001 file4096
+2 Jan 1 2001 file1024
+512 Jan 1 2001 file262144
+8 Jan 1 2001 file4096
+2 Jan 1 2001 file1024
+512 Jan 1 2001 file262144
+8 Jan 1 2001 file4096
+# LS_BLOCK_SIZE=1K
+1 Jan 1 2001 file1024
+256 Jan 1 2001 file262144
+4 Jan 1 2001 file4096
+1 Jan 1 2001 file1024
+256 Jan 1 2001 file262144
+4 Jan 1 2001 file4096
+1 Jan 1 2001 file1024
+256 Jan 1 2001 file262144
+4 Jan 1 2001 file4096
+# LS_BLOCK_SIZE=1KiB
+1 Jan 1 2001 file1024
+256 Jan 1 2001 file262144
+4 Jan 1 2001 file4096
+1 Jan 1 2001 file1024
+256 Jan 1 2001 file262144
+4 Jan 1 2001 file4096
+1 Jan 1 2001 file1024
+256 Jan 1 2001 file262144
+4 Jan 1 2001 file4096
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/ls/capability.sh b/tests/ls/capability.sh
new file mode 100755
index 0000000..8e2fc78
--- /dev/null
+++ b/tests/ls/capability.sh
@@ -0,0 +1,63 @@
+#!/bin/sh
+# Ensure "ls --color" properly colors name of file with capability.
+
+# 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_ ls printf
+require_root_
+
+grep '^#define HAVE_CAP 1' $CONFIG_HEADER > /dev/null \
+ || skip_ "configured without libcap support"
+
+(setcap --help) 2>&1 |grep 'usage: setcap' > /dev/null \
+ || skip_ "setcap utility not found"
+
+# Don't let a different umask perturb the results.
+umask 22
+
+# We create 2 files of the same name as
+# before coreutils 8.1 only the name rather than
+# the full path was used to read the capabilities
+# thus giving false positives and negatives.
+mkdir test test/dir
+cd test
+touch cap_pos dir/cap_pos dir/cap_neg
+for file in cap_pos dir/cap_neg; do
+ setcap 'cap_net_bind_service=ep' $file ||
+ skip_ "setcap doesn't work"
+done
+
+code='30;41'
+# Note we explicitly disable "executable" coloring
+# so that capability coloring is not dependent on it,
+# as was the case before coreutils 8.1
+for ex in '' ex=:; do
+ LS_COLORS="di=:${ex}ca=$code" \
+ ls --color=always cap_pos dir > out || fail=1
+
+ env printf "\
+\e[0m\e[${code}mcap_pos\e[0m
+
+dir:
+\e[${code}mcap_neg\e[0m
+cap_pos
+" > out_ok || framework_failure_
+
+ compare out out_ok || fail=1
+done
+
+Exit $fail
diff --git a/tests/ls/classify.sh b/tests/ls/classify.sh
new file mode 100755
index 0000000..e1c73e4
--- /dev/null
+++ b/tests/ls/classify.sh
@@ -0,0 +1,63 @@
+#!/bin/sh
+# Test --classify processing
+
+# Copyright (C) 2020-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_ ls
+
+mkdir testdir || framework_failure_
+cd testdir || framework_failure_
+mkdir dir || framework_failure_
+touch regular executable || framework_failure_
+chmod a+x executable || framework_failure_
+ln -s regular slink-reg || framework_failure_
+ln -s dir slink-dir || framework_failure_
+ln -s nowhere slink-dangle || framework_failure_
+mknod block b 20 20 2> /dev/null && block="block
+"
+mknod char c 10 10 2> /dev/null && char="char
+"
+mkfifo_or_skip_ fifo
+cd ..
+
+cat <<EOF > exp
+$block${char}dir/
+executable*
+fifo|
+regular
+slink-dangle@
+slink-dir@
+slink-reg@
+EOF
+sed 's/[*/@|]//' exp > exp2 || framework_failure_
+
+ls --classify testdir > out || fail=1
+ls --classify=always testdir > out2 || fail=1
+ls --classify=auto testdir > out3 || fail=1
+ls --classify=never testdir > out4 || fail=1
+
+compare exp out || fail=1
+
+compare exp out2 || fail=1
+
+compare exp2 out3 || fail=1
+
+compare exp2 out4 || fail=1
+
+returns_ 1 ls --classify=invalid || fail=1
+
+Exit $fail
diff --git a/tests/ls/color-clear-to-eol.sh b/tests/ls/color-clear-to-eol.sh
new file mode 100755
index 0000000..d8d502e
--- /dev/null
+++ b/tests/ls/color-clear-to-eol.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+# ensure that ls --color works well when a colored name is wrapped
+
+# 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_ ls
+
+long_name=zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.foo
+touch $long_name || framework_failure_
+
+e='\33'
+color_code='0;31;42'
+c_pre="$e[0m$e[${color_code}m"
+c_post="$e[0m$e[K\n"
+printf "$c_pre$long_name$c_post\n" > exp || framework_failure_
+
+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 || framework_failure_
+
+sed 's/.*T //' out > k && mv k out
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/ls/color-dtype-dir.sh b/tests/ls/color-dtype-dir.sh
new file mode 100755
index 0000000..857faef
--- /dev/null
+++ b/tests/ls/color-dtype-dir.sh
@@ -0,0 +1,64 @@
+#!/bin/sh
+# Ensure "ls --color" properly colors other-writable and sticky directories.
+# Before coreutils-6.2, this test would fail, coloring all three
+# directories the same as the first one -- but only on a file system
+# with dirent.d_type support.
+
+# Copyright (C) 2006-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_ ls
+
+# Don't let a different umask perturb the results.
+umask 22
+
+mkdir d other-writable sticky || framework_failure_
+chmod o+w other-writable || framework_failure_
+chmod o+t sticky || framework_failure_
+
+
+TERM=xterm ls --color=always > out || fail=1
+cat -A out > o1 || framework_failure_
+mv o1 out || framework_failure_
+
+cat <<\EOF > exp || framework_failure_
+^[[0m^[[01;34md^[[0m$
+^[[34;42mother-writable^[[0m$
+out$
+^[[37;44msticky^[[0m$
+EOF
+
+compare exp out || fail=1
+
+rm exp || framework_failure_
+
+# 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
+mv o1 out || fail=1
+
+cat <<\EOF > exp || framework_failure_
+^[[0m^[[01;34md^[[0m$
+^[[01;34mother-writable^[[0m$
+out$
+^[[37;44msticky^[[0m$
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/ls/color-ext.sh b/tests/ls/color-ext.sh
new file mode 100755
index 0000000..c9d3c0a
--- /dev/null
+++ b/tests/ls/color-ext.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+# Ensure "ls --color" properly colors file name extensions.
+
+# Copyright (C) 2018-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_ ls
+working_umask_or_skip_
+
+touch img1.jpg IMG2.JPG file1.z file2.Z || framework_failure_
+code_jpg='01;35'
+code_z='01;31'
+c0=$(printf '\033[0m')
+c_jpg=$(printf '\033[%sm' $code_jpg)
+c_z=$(printf '\033[%sm' $code_z)
+
+LS_COLORS="*.jpg=$code_jpg:*.Z=$code_z" ls -U1 --color=always \
+ img1.jpg IMG2.JPG file1.z file2.Z > out || fail=1
+printf "$c0\
+${c_jpg}img1.jpg$c0
+${c_jpg}IMG2.JPG$c0
+${c_z}file1.z$c0
+${c_z}file2.Z$c0
+" > out_ok || framework_failure_
+compare out out_ok || fail=1
+
+
+Exit $fail
diff --git a/tests/ls/color-norm.sh b/tests/ls/color-norm.sh
new file mode 100755
index 0000000..6c9c3f6
--- /dev/null
+++ b/tests/ls/color-norm.sh
@@ -0,0 +1,84 @@
+#!/bin/sh
+# Ensure "ls --color" properly colors "normal" text and files.
+# I.e., that it uses NORMAL to style non file name output and
+# file names with no associated color (unless FILE is also set).
+
+# Copyright (C) 2010-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_ ls
+
+# Don't let a different umask perturb the results.
+umask 22
+
+# Output time as something constant
+export TIME_STYLE="+norm"
+
+# helper to strip ls columns up to "norm" time
+qls() { sed 's/-r.*norm/norm/'; }
+
+touch exe || framework_failure_
+chmod u+x exe || framework_failure_
+touch nocolor || framework_failure_
+
+TCOLORS="no=7:ex=01;32"
+
+# Uncolored file names inherit NORMAL attributes.
+LS_COLORS=$TCOLORS ls -gGU --color exe nocolor | qls >> out || fail=1
+LS_COLORS=$TCOLORS ls -xU --color exe nocolor >> out || fail=1
+LS_COLORS=$TCOLORS ls -gGU --color nocolor exe | qls >> out || fail=1
+LS_COLORS=$TCOLORS ls -xU --color nocolor exe >> out || fail=1
+
+# NORMAL does not override FILE though
+LS_COLORS=$TCOLORS:fi=1 ls -gGU --color nocolor exe | qls >> out || fail=1
+
+# Support uncolored ordinary files that do _not_ inherit from NORMAL.
+# Note there is a redundant RESET output before a non colored
+# file in this case which may be removed in future.
+LS_COLORS=$TCOLORS:fi= ls -gGU --color nocolor exe | qls >> out || fail=1
+LS_COLORS=$TCOLORS:fi=0 ls -gGU --color nocolor exe | qls >> out || fail=1
+
+# A caveat worth noting is that commas (-m), indicator chars (-F)
+# and the "total" line, do not currently use NORMAL attributes
+LS_COLORS=$TCOLORS ls -mFU --color nocolor exe >> out || fail=1
+
+# Ensure no coloring is done unless enabled
+LS_COLORS=$TCOLORS ls -gGU nocolor exe | qls >> out || fail=1
+
+cat -A out > out.display || framework_failure_
+mv out.display out || framework_failure_
+
+cat <<\EOF > exp || framework_failure_
+^[[0m^[[7mnorm ^[[m^[[01;32mexe^[[0m$
+^[[7mnorm nocolor^[[0m$
+^[[0m^[[7m^[[m^[[01;32mexe^[[0m ^[[7mnocolor^[[0m$
+^[[0m^[[7mnorm nocolor^[[0m$
+^[[7mnorm ^[[m^[[01;32mexe^[[0m$
+^[[0m^[[7mnocolor^[[0m ^[[7m^[[m^[[01;32mexe^[[0m$
+^[[0m^[[7mnorm ^[[m^[[1mnocolor^[[0m$
+^[[7mnorm ^[[m^[[01;32mexe^[[0m$
+^[[0m^[[7mnorm ^[[m^[[mnocolor^[[0m$
+^[[7mnorm ^[[m^[[01;32mexe^[[0m$
+^[[0m^[[7mnorm ^[[m^[[0mnocolor^[[0m$
+^[[7mnorm ^[[m^[[01;32mexe^[[0m$
+^[[0m^[[7mnocolor^[[0m, ^[[7m^[[m^[[01;32mexe^[[0m*$
+norm nocolor$
+norm exe$
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/ls/color-term.sh b/tests/ls/color-term.sh
new file mode 100755
index 0000000..06c06c1
--- /dev/null
+++ b/tests/ls/color-term.sh
@@ -0,0 +1,48 @@
+#!/bin/sh
+# Ensure "ls --color" doesn't output colors for TERM=dumb
+
+# 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_ ls
+
+# Output time as something constant
+export TIME_STYLE="+norm"
+
+touch exe || framework_failure_
+chmod u+x exe || framework_failure_
+
+# output colors
+LS_COLORS='' COLORTERM='nonempty' TERM='' ls --color=always exe >> out || fail=1
+LS_COLORS='' COLORTERM='' TERM='xterm' ls --color=always exe >> out || fail=1
+
+# Don't output colors
+LS_COLORS='' COLORTERM='' TERM='dumb' ls --color=always exe >> out || fail=1
+LS_COLORS='' COLORTERM='' TERM='' ls --color=always exe >> out || fail=1
+
+cat -A out > out.display || framework_failure_
+mv out.display out || framework_failure_
+
+cat <<\EOF > exp || framework_failure_
+^[[0m^[[01;32mexe^[[0m$
+^[[0m^[[01;32mexe^[[0m$
+exe$
+exe$
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/ls/dangle.sh b/tests/ls/dangle.sh
new file mode 100755
index 0000000..8e89afe
--- /dev/null
+++ b/tests/ls/dangle.sh
@@ -0,0 +1,64 @@
+#!/bin/sh
+# Make sure ls properly handles dangling symlinks vs. ls's -L, -H, options.
+
+# 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_ ls
+
+LS_MINOR_PROBLEM=1
+LS_FAILURE=2
+
+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_
+
+# This must exit nonzero.
+returns_ $LS_FAILURE ls -L dangle > /dev/null 2>&1 || fail=1
+# So must this.
+returns_ $LS_FAILURE ls -H dangle > /dev/null 2>&1 || fail=1
+
+# This must exit successfully.
+ls dangle >> out || fail=1
+
+ls slink-to-dir >> out 2>&1 || fail=1
+ls -H slink-to-dir >> out 2>&1 || fail=1
+ls -L slink-to-dir >> out 2>&1 || fail=1
+
+cat <<\EOF > exp
+dangle
+sub
+sub
+sub
+EOF
+
+compare exp out || fail=1
+
+# Ensure that ls -Li prints "?" as the inode of a dangling symlink.
+rm -f out
+returns_ $LS_MINOR_PROBLEM ls -Li d > out 2>/dev/null || fail=1
+compare subdir_Li_exp out || fail=1
+
+# Ensure that ls -Ls prints "?" as the allocation of a dangling symlink.
+rm -f out
+returns_ $LS_MINOR_PROBLEM ls -Ls d > out 2>/dev/null || fail=1
+compare subdir_Ls_exp out || fail=1
+
+Exit $fail
diff --git a/tests/ls/dired.sh b/tests/ls/dired.sh
new file mode 100755
index 0000000..1b67c1a
--- /dev/null
+++ b/tests/ls/dired.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+# make sure --dired option works
+
+# Copyright (C) 2001-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_ ls
+
+mkdir dir || framework_failure_
+
+
+LC_MESSAGES=C ls -lR --dired dir > out || fail=1
+cat <<EOF > exp
+ dir:
+ total 0
+//SUBDIRED// 2 5
+//DIRED-OPTIONS// --quoting-style=literal
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/ls/file-type.sh b/tests/ls/file-type.sh
new file mode 100755
index 0000000..430637e
--- /dev/null
+++ b/tests/ls/file-type.sh
@@ -0,0 +1,65 @@
+#!/bin/sh
+# contrast ls -F, ls -p, and ls --indicator-style=file-type
+
+# Copyright (C) 2002-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_ ls
+
+mkdir sub
+cd sub
+mkdir dir
+touch regular executable
+chmod a+x executable
+ln -s regular slink-reg
+ln -s dir slink-dir
+ln -s nowhere slink-dangle
+mknod block b 20 20 2> /dev/null && block="block
+"
+mknod char c 10 10 2> /dev/null && char="char
+"
+mkfifo_or_skip_ fifo
+cd ..
+
+
+
+ls -F sub > out || fail=1
+cat <<EOF > exp
+$block${char}dir/
+executable*
+fifo|
+regular
+slink-dangle@
+slink-dir@
+slink-reg@
+EOF
+
+sed 's/\*//' exp > exp2
+ls --indicator-style=file-type sub > out2 || fail=1
+
+sed 's/[@|]$//' exp2 > exp3
+ls -p sub > out3 || fail=1
+
+compare exp out || fail=1
+
+compare exp2 out2 || fail=1
+
+compare exp3 out3 || fail=1
+
+ls --color=auto -F sub > out || fail=1
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/ls/follow-slink.sh b/tests/ls/follow-slink.sh
new file mode 100755
index 0000000..7f3eb19
--- /dev/null
+++ b/tests/ls/follow-slink.sh
@@ -0,0 +1,63 @@
+#!/bin/sh
+# make sure ls -L always follows symlinks
+
+# 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_ ls
+
+LS_FAILURE=2
+
+# Isolate output files from directory being listed
+mkdir dir dir/sub dir1 || framework_failure_
+cd dir || framework_failure_
+ln -s link link || framework_failure_
+ln -s ../../dir1 sub/link-to-dir || framework_failure_
+
+# Make sure the symlink was created.
+# 'ln -s link link' succeeds, but creates no file on
+# systems running some DJGPP-2.03 libc.
+ls -F link > /dev/null || framework_failure_
+
+
+# When explicitly listing a broken link, the command must fail.
+returns_ $LS_FAILURE ls -L link 2> /dev/null || fail=1
+
+# When encountering a broken link implicitly, Solaris 9 and OpenBSD 3.4
+# list the link, provided no further information about the link needed
+# to be printed. Since POSIX does not specify one way or the other, we
+# opt for compatibility (this was broken in 5.3.0 through 5.94).
+LC_ALL=C ls -L > ../out-L || fail=1
+LC_ALL=C ls -FLR sub > ../out-FLR-sub || fail=1
+
+cd .. || fail=1
+
+cat <<\EOF > exp-L
+link
+sub
+EOF
+
+cat <<\EOF > exp-FLR-sub
+sub:
+link-to-dir/
+
+sub/link-to-dir:
+EOF
+
+compare exp-L out-L || fail=1
+compare exp-FLR-sub out-FLR-sub || fail=1
+
+Exit $fail
diff --git a/tests/ls/getxattr-speedup.sh b/tests/ls/getxattr-speedup.sh
new file mode 100755
index 0000000..bd8ec5e
--- /dev/null
+++ b/tests/ls/getxattr-speedup.sh
@@ -0,0 +1,66 @@
+#!/bin/sh
+# Show that we've eliminated most of ls' failing getxattr syscalls,
+# regardless of how many files are in a directory we list.
+# This test is skipped on systems that lack LD_PRELOAD support; that's fine.
+# Similarly, on a system that lacks getxattr altogether, skipping it is fine.
+
+# 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_ ls
+require_gcc_shared_
+
+# Replace each getxattr and lgetxattr call with a call to these stubs.
+# Count those and write the total number of calls to the file "x"
+# via a global destructor.
+cat > k.c <<'EOF' || framework_failure_
+#include <errno.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+static unsigned long int n_calls;
+
+static void __attribute__ ((destructor))
+print_call_count (void)
+{
+ FILE *fp = fopen ("x", "w"); if (!fp) return;
+ fprintf (fp, "%lu\n", n_calls); fclose (fp);
+}
+
+static ssize_t incr () { ++n_calls; errno = ENOTSUP; return -1; }
+ssize_t getxattr (const char *path, const char *name, void *value, size_t size)
+{ return incr (); }
+ssize_t lgetxattr(const char *path, const char *name, void *value, size_t size)
+{ return incr (); }
+EOF
+
+# Then compile/link it:
+gcc_shared_ k.c k.so \
+ || framework_failure_ 'failed to build shared library'
+
+# Create a few files:
+seq 20 | xargs touch || framework_failure_
+
+# Finally, run the test:
+LD_PRELOAD=$LD_PRELOAD:./k.so ls --color=always -l . || fail=1
+
+test -f x || skip_ "internal test failure: maybe LD_PRELOAD doesn't work?"
+
+# Ensure that there were no more than 3 *getxattr calls.
+n_calls=$(cat x)
+test "$n_calls" -le 3 || fail=1
+
+Exit $fail
diff --git a/tests/ls/group-dirs.sh b/tests/ls/group-dirs.sh
new file mode 100755
index 0000000..6521142
--- /dev/null
+++ b/tests/ls/group-dirs.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+# test --group-directories-first
+
+# Copyright (C) 2018-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_ ls
+
+# Isolate output files from directory being listed
+mkdir dir dir/b || framework_failure_
+touch dir/a || framework_failure_
+ln -s b dir/bl || framework_failure_
+
+ls --group dir > out || fail=1
+cat <<\EOF > exp
+b
+bl
+a
+EOF
+compare exp out || fail=1
+
+ls --group -d dir/* > out || fail=1
+cat <<\EOF > exp
+dir/b
+dir/bl
+dir/a
+EOF
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/ls/hex-option.sh b/tests/ls/hex-option.sh
new file mode 100755
index 0000000..0f9d774
--- /dev/null
+++ b/tests/ls/hex-option.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+# accept hex/oct numbers to -w and -T
+
+# 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_ ls
+
+ls -x -T0x10 -w010 || fail=1
+
+Exit $fail
diff --git a/tests/ls/hyperlink.sh b/tests/ls/hyperlink.sh
new file mode 100755
index 0000000..e87b3cf
--- /dev/null
+++ b/tests/ls/hyperlink.sh
@@ -0,0 +1,63 @@
+#!/bin/sh
+# Test --hyperlink processing
+
+# 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_ ls
+
+# lookup based on first letter
+encode() {
+ printf '%s\n' \
+ 'sp%20ace' 'ques%3ftion' 'back%5cslash' 'encoded%253Fquestion' 'testdir' \
+ "$1" |
+ sort -k1,1.1 -s | uniq -w1 -d
+}
+
+ls_encoded() {
+ ef=$(encode "$1")
+ echo "$ef" | grep -q 'dir$' && dir=: || dir=''
+ printf '\033]8;;file:///%s\a%s\033]8;;\a%s\n' \
+ "$ef" "$1" "$dir"
+}
+
+# These could be encoded, so remove from consideration
+strip_host_and_path() {
+ sed 's|file://.*/|file:///|'
+}
+
+mkdir testdir || framework_failure_
+(
+cd testdir
+ls_encoded "testdir" > ../exp.t || framework_failure_
+for f in 'back\slash' 'encoded%3Fquestion' 'ques?tion' 'sp ace'; do
+ touch "$f" || framework_failure_
+ ls_encoded "$f" >> ../exp.t || framework_failure_
+done
+)
+ln -s testdir testdirl || framework_failure_
+(cat exp.t && printf '\n' && sed 's/[^\/]testdir/&l/' exp.t) > exp \
+ || framework_failure_
+ls --hyper testdir testdirl >out.t || fail=1
+strip_host_and_path <out.t >out || framework_failure_
+compare exp out || fail=1
+
+ln -s '/probably_missing' testlink || framework_failure_
+ls -l --hyper testlink > out.t || fail=1
+strip_host_and_path <out.t >out || framework_failure_
+grep 'file:///probably_missing' out || fail=1
+
+Exit $fail
diff --git a/tests/ls/infloop.sh b/tests/ls/infloop.sh
new file mode 100755
index 0000000..f314737
--- /dev/null
+++ b/tests/ls/infloop.sh
@@ -0,0 +1,41 @@
+#!/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-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_ ls
+
+mkdir loop || framework_failure_
+ln -s ../loop loop/sub || framework_failure_
+
+cat <<\EOF > exp-out || framework_failure_
+loop:
+sub
+EOF
+
+cat <<\EOF > exp-err || framework_failure_
+ls: loop/sub: not listing already-listed directory
+EOF
+
+# Ensure that ls exits with status 2 upon detecting a cycle
+returns_ 2 timeout 10 ls -RL loop >out 2>err || fail=1
+
+compare exp-err err || fail=1
+compare exp-out out || fail=1
+
+Exit $fail
diff --git a/tests/ls/inode.sh b/tests/ls/inode.sh
new file mode 100755
index 0000000..807ec29
--- /dev/null
+++ b/tests/ls/inode.sh
@@ -0,0 +1,65 @@
+#!/bin/sh
+# Make sure that ls -i works properly on symlinks.
+
+# 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_ ls
+
+touch f || framework_failure_
+ln -s f slink || framework_failure_
+
+
+# When listed explicitly:
+
+set x $(ls -Ci f slink); shift
+test $# = 4 || fail=1
+# The inode numbers should differ.
+test "$1" != "$3" || fail=1
+
+set x $(ls -CLi f slink); shift
+test $# = 4 || fail=1
+# With -L, they must be the same.
+test "$1" = "$3" || fail=1
+
+set x $(ls -CHi f slink); shift
+test $# = 4 || fail=1
+# With -H, they must be the same, too, from the command line.
+# Note that POSIX says -H must make ls dereference only
+# symlinks (specified on the command line) to directories,
+# but the historical BSD meaning of -H is to dereference
+# any symlink given on the command line. For compatibility GNU ls
+# implements the BSD semantics.
+test "$1" = "$3" || fail=1
+
+# When listed from a directory:
+
+set x $(ls -Ci); shift
+test $# = 4 || fail=1
+# The inode numbers should differ.
+test "$1" != "$3" || fail=1
+
+set x $(ls -CLi); shift
+test $# = 4 || fail=1
+# With -L, they must be the same.
+test "$1" = "$3" || fail=1
+
+set x $(ls -CHi); shift
+test $# = 4 || fail=1
+# With -H, they must be different from inside a directory.
+test "$1" != "$3" || fail=1
+
+Exit $fail
diff --git a/tests/ls/m-option.sh b/tests/ls/m-option.sh
new file mode 100755
index 0000000..eba7df9
--- /dev/null
+++ b/tests/ls/m-option.sh
@@ -0,0 +1,40 @@
+#!/bin/sh
+# exercise the -m option
+
+# 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_ ls
+
+seq 2000 > b || framework_failure_
+touch a || framework_failure_
+
+
+# Before coreutils-5.1.1, the following would output a space after the comma.
+ls -w2 -m a b > out || fail=1
+
+# Before coreutils-5.1.1, the following would produce leading white space.
+# All of the sed business is because the sizes are not portable.
+ls -sm a b | sed 's/^[0-9]/0/;s/, [0-9][0-9]* b/, 12 b/' >> out || fail=1
+cat <<\EOF > exp || framework_failure_
+a,
+b
+0 a, 12 b
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/ls/multihardlink.sh b/tests/ls/multihardlink.sh
new file mode 100755
index 0000000..c3787a8
--- /dev/null
+++ b/tests/ls/multihardlink.sh
@@ -0,0 +1,80 @@
+#!/bin/sh
+# Ensure "ls --color" properly colors names of hard linked 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_ ls
+working_umask_or_skip_
+
+touch file file1 || framework_failure_
+ln file1 file2 || skip_ "can't create hard link"
+code_mh='44;37'
+code_ex='01;32'
+code_png='01;35'
+c0=$(printf '\033[0m')
+c_mh=$(printf '\033[%sm' $code_mh)
+c_ex=$(printf '\033[%sm' $code_ex)
+c_png=$(printf '\033[%sm' $code_png)
+
+# regular file - not hard linked
+LS_COLORS="mh=$code_mh" ls -U1 --color=always file > out || fail=1
+printf "file\n" > out_ok || framework_failure_
+compare out out_ok || fail=1
+
+# hard links
+LS_COLORS="mh=$code_mh" ls -U1 --color=always file1 file2 > out || fail=1
+printf "$c0${c_mh}file1$c0
+${c_mh}file2$c0
+" > out_ok || framework_failure_
+compare out out_ok || fail=1
+
+# hard links and png (hard link coloring takes precedence)
+mv file2 file2.png || framework_failure_
+LS_COLORS="mh=$code_mh:*.png=$code_png" ls -U1 --color=always file1 file2.png \
+ > out || fail=1
+printf "$c0${c_mh}file1$c0
+${c_mh}file2.png$c0
+" > out_ok || framework_failure_
+compare out out_ok || fail=1
+
+# hard links and exe (exe coloring takes precedence)
+chmod a+x file2.png || framework_failure_
+LS_COLORS="mh=$code_mh:*.png=$code_png:ex=$code_ex" \
+ ls -U1 --color=always file1 file2.png > out || fail=1
+chmod a-x file2.png || framework_failure_
+printf "$c0${c_ex}file1$c0
+${c_ex}file2.png$c0
+" > out_ok || framework_failure_
+compare out out_ok || fail=1
+
+# hard links and png (hard link coloring disabled => png coloring enabled)
+LS_COLORS="mh=00:*.png=$code_png" ls -U1 --color=always file1 file2.png > out \
+ || fail=1
+printf "file1
+$c0${c_png}file2.png$c0
+" > out_ok || framework_failure_
+compare out out_ok || fail=1
+
+# hard links and png (hard link coloring not enabled explicitly => png coloring)
+LS_COLORS="*.png=$code_png" ls -U1 --color=always file1 file2.png > out \
+ || fail=1
+printf "file1
+$c0${c_png}file2.png$c0
+" > out_ok || framework_failure_
+compare out out_ok || fail=1
+
+Exit $fail
diff --git a/tests/ls/nameless-uid.sh b/tests/ls/nameless-uid.sh
new file mode 100755
index 0000000..8071456
--- /dev/null
+++ b/tests/ls/nameless-uid.sh
@@ -0,0 +1,40 @@
+#!/bin/sh
+# Ensure that ls -l works on files with nameless uid and/or gid
+
+# Copyright (C) 2006-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_ ls
+
+require_root_
+require_perl_
+
+nameless_uid=$($PERL -e '
+ foreach my $i (1000..16*1024) { getpwuid $i or (print "$i\n"), exit }
+')
+
+if test x$nameless_uid = x; then
+ skip_ "couldn't find a nameless UID"
+fi
+
+touch f || framework_failure_
+chown $nameless_uid f || framework_failure_
+
+
+set -- $(ls -o f) || fail=1
+test $3 = $nameless_uid || fail=1
+
+Exit $fail
diff --git a/tests/ls/no-arg.sh b/tests/ls/no-arg.sh
new file mode 100755
index 0000000..e9d2f25
--- /dev/null
+++ b/tests/ls/no-arg.sh
@@ -0,0 +1,56 @@
+#!/bin/sh
+# make sure ls and 'ls -R' do the right thing when invoked with no arguments.
+
+# Copyright (C) 2001-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_ ls
+
+mkdir -p dir/subdir || framework_failure_
+touch dir/subdir/file2 || framework_failure_
+ln -s f symlink || framework_failure_
+
+cat > exp <<\EOF || framework_failure_
+dir
+exp
+out
+symlink
+EOF
+
+
+ls -1 > out || fail=1
+
+compare exp out || fail=1
+
+cat > exp <<\EOF
+.:
+dir
+exp
+out
+symlink
+
+./dir:
+subdir
+
+./dir/subdir:
+file2
+EOF
+
+ls -R1 > out || fail=1
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/ls/no-cap.sh b/tests/ls/no-cap.sh
new file mode 100755
index 0000000..864e4a5
--- /dev/null
+++ b/tests/ls/no-cap.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+# ensure that an empty "ca=" attribute disables ls's capability-checking
+
+# 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_ ls
+require_strace_ capget
+
+LS_COLORS=ca=1; export LS_COLORS
+strace -e capget ls --color=always > /dev/null 2> out || fail=1
+$EGREP 'capget\(' out || skip_ "your ls doesn't call capget"
+
+rm -f out
+
+LS_COLORS=ca=:; export LS_COLORS
+strace -e capget ls --color=always > /dev/null 2> out || fail=1
+$EGREP 'capget\(' out && fail=1
+
+Exit $fail
diff --git a/tests/ls/quote-align.sh b/tests/ls/quote-align.sh
new file mode 100755
index 0000000..56b6095
--- /dev/null
+++ b/tests/ls/quote-align.sh
@@ -0,0 +1,62 @@
+#!/bin/sh
+# test quote alignment combinations
+
+# Copyright (C) 2016-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_ ls
+
+dirname='dir:name'
+mkdir "$dirname" || framework_failure_
+touch "$dirname/a b" "$dirname/c.foo" || framework_failure_
+
+e=$(printf '\033')
+color_code='0;31;42'
+c_pre="$e[0m$e[${color_code}m"
+c_post="$e[0m"
+
+cat <<EOF >exp || framework_failure_
+'$dirname':
+'a b' ${c_pre}c.foo${c_post}
+'$dirname':
+'a b' ${c_pre}c.foo${c_post}
+'$dirname':
+'a b'
+ ${c_pre}c.foo${c_post}
+'$dirname':
+'a b'
+${c_pre}c.foo${c_post}
+'$dirname':
+'a b', ${c_pre}c.foo${c_post}
+'$dirname':
+'a b' ${c_pre}c.foo${c_post}
+
+EOF
+
+for opt in '-w0 -x' '-x' '-og' '-1' '-m' '-C'; do
+ env TERM=xterm LS_COLORS="*.foo=$color_code" TIME_STYLE=+T \
+ ls $opt -R --quoting=shell-escape --color=always "$dirname" >> out || fail=1
+done
+
+# Append a newline, to accommodate less-capable versions of sed.
+echo >> out || framework_failure_
+
+# Strip possible varying portion of long format
+sed -e 's/.*T //' -e '/^total/d' out > k && mv k out
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/ls/readdir-mountpoint-inode.sh b/tests/ls/readdir-mountpoint-inode.sh
new file mode 100755
index 0000000..e6162bb
--- /dev/null
+++ b/tests/ls/readdir-mountpoint-inode.sh
@@ -0,0 +1,73 @@
+#!/bin/sh
+# ensure that ls -i works also for mount points
+
+# 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_ ls
+
+# We use --local here so as to not activate
+# potentially very many remote mounts.
+df --local --out=target | sed -n '/^\/./p' > mount_points
+test -s mount_points ||
+ skip_ "this test requires a non-root mount point"
+
+# Given e.g., /dev/shm, produce the list of GNU ls options that
+# let us list just that entry using readdir data from its parent:
+# ls -i -I '[^s]*' -I 's[^h]*' -I 'sh[^m]*' -I 'shm?*' -I '.?*' \
+# -I '?' -I '??' /dev
+
+ls_ignore_options()
+{
+ name=$1
+ opts="-I '.?*' -I '$name?*'"
+ while :; do
+ glob=$(echo "$name"|sed 's/\(.*\)\(.\)$/\1[^\2]*/')
+ opts="$opts -I '$glob'"
+ name=$(echo "$name"|sed 's/.$//')
+ test -z "$name" && break
+ glob=$(echo "$name"|sed 's/./?/g')
+ opts="$opts -I '$glob'"
+ done
+ echo "$opts"
+}
+
+inode_via_readdir()
+{
+ mount_point=$1
+ base=$(basename "$mount_point")
+ case "$base" in
+ .*) skip_ 'mount point component starts with "."' ;;
+ *[*?]*) skip_ 'mount point component contains "?" or "*"' ;;
+ esac
+ opts=$(ls_ignore_options "$base")
+ parent_dir=$(dirname "$mount_point")
+ ls_out=$(eval "ls -i $opts '$parent_dir'")
+ test $? -eq 0 || \
+ skip_ "'$parent_dir' is not readable for current user"
+ echo $ls_out | sed 's/ .*//'
+}
+
+while read dir; do
+ readdir_inode=$(inode_via_readdir "$dir")
+ test $? = 77 && continue
+ stat_inode=$(timeout 1 stat --format=%i "$dir")
+ # If stat fails or says the inode is 0, skip $dir.
+ case $stat_inode in 0|'') continue;; esac
+ test "$readdir_inode" = "$stat_inode" || fail=1
+done < mount_points
+
+Exit $fail
diff --git a/tests/ls/recursive.sh b/tests/ls/recursive.sh
new file mode 100755
index 0000000..db00a74
--- /dev/null
+++ b/tests/ls/recursive.sh
@@ -0,0 +1,62 @@
+#!/bin/sh
+# 4.1.1 and 4.1.2 had a bug whereby some recursive listings
+# didn't include a blank line between per-directory groups of files.
+
+# Copyright (C) 2001-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_ ls
+
+mkdir x y a b c a/1 a/2 a/3 || framework_failure_
+touch f a/1/I a/1/II || framework_failure_
+
+
+# This first example is from Andreas Schwab's bug report.
+ls -R1 a b c > out || fail=1
+cat <<EOF > exp
+a:
+1
+2
+3
+
+a/1:
+I
+II
+
+a/2:
+
+a/3:
+
+b:
+
+c:
+EOF
+
+compare exp out || fail=1
+
+rm -rf out exp
+ls -R1 x y f > out || fail=1
+cat <<EOF > exp
+f
+
+x:
+
+y:
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/ls/removed-directory.sh b/tests/ls/removed-directory.sh
new file mode 100755
index 0000000..85339ca
--- /dev/null
+++ b/tests/ls/removed-directory.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+# If ls is asked to list a removed directory (e.g., the parent process's
+# current working directory has been removed by another process), it
+# should not emit an error message merely because the directory is removed.
+
+# Copyright (C) 2020-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_ ls
+
+cwd=$(pwd)
+mkdir d || framework_failure_
+cd d || framework_failure_
+rmdir ../d || skip_ "can't remove working directory on this platform"
+
+# On NFS, 'ls' would run into the error "Stale file handle".
+test -d . || skip_ "can't examine removed working directory on this platform"
+
+ls >"$cwd"/out 2>"$cwd"/err || fail=1
+cd "$cwd" || framework_failure_
+
+compare /dev/null out || fail=1
+compare /dev/null err || fail=1
+
+Exit $fail
diff --git a/tests/ls/root-rel-symlink-color.sh b/tests/ls/root-rel-symlink-color.sh
new file mode 100755
index 0000000..c6da9a1
--- /dev/null
+++ b/tests/ls/root-rel-symlink-color.sh
@@ -0,0 +1,51 @@
+#!/bin/sh
+# Exercise the 8.17 ls bug with coloring relative-named symlinks in "/".
+
+# 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_ ls test
+
+symlink_to_rel=
+for i in /*; do
+ # Skip non-symlinks:
+ env test -h "$i" || continue
+
+ # Skip dangling symlinks:
+ env test -e "$i" || continue
+
+ # Skip any symlink-to-absolute-name:
+ case $(readlink "$i") in /*) continue ;; esac
+
+ symlink_to_rel=$i
+ break
+done
+
+test -z "$symlink_to_rel" \
+ && skip_ no relative symlink in /
+
+e='\33'
+color_code='01;36'
+c_pre="$e[0m$e[${color_code}m"
+c_post="$e[0m"
+printf "$c_pre$symlink_to_rel$c_post\n" > exp || framework_failure_
+
+env TERM=xterm LS_COLORS="ln=$color_code:or=1;31;42" \
+ ls -d --color=always "$symlink_to_rel" > out || fail=1
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/ls/rt-1.sh b/tests/ls/rt-1.sh
new file mode 100755
index 0000000..2124be8
--- /dev/null
+++ b/tests/ls/rt-1.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+# Make sure name is used as secondary key when sorting on mtime or ctime.
+
+# Copyright (C) 1998-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_ ls touch
+
+date=1998-01-15
+
+touch -d "$date" c || framework_failure_
+touch -d "$date" a || framework_failure_
+touch -d "$date" b || framework_failure_
+
+
+ls -1t a b c > out || fail=1
+cat <<EOF > exp
+a
+b
+c
+EOF
+compare exp out || fail=1
+
+rm -rf out exp
+ls -1rt a b c > out || fail=1
+cat <<EOF > exp
+c
+b
+a
+EOF
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/ls/selinux-segfault.sh b/tests/ls/selinux-segfault.sh
new file mode 100755
index 0000000..c071978
--- /dev/null
+++ b/tests/ls/selinux-segfault.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+# Ensure we don't segfault in selinux handling
+
+# 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_ ls
+
+# ls -l /proc/sys would segfault when built against libselinux1 2.0.15-2+b1
+f=/proc/sys
+test -r $f || f=.
+ls -l $f > out || fail=1
+
+# ls <= 8.32 would segfault when printing
+# the security context of broken symlink targets
+mkdir sedir || framework_failure_
+ln -sf missing sedir/broken || framework_failure_
+returns_ 1 ls -L -R -Z -m sedir > out || fail=1
+
+Exit $fail
diff --git a/tests/ls/slink-acl.sh b/tests/ls/slink-acl.sh
new file mode 100755
index 0000000..2b6cf2c
--- /dev/null
+++ b/tests/ls/slink-acl.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+# verify that ls -lL works when applied to a symlink to an ACL'd file
+
+# 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_ ls
+
+require_setfacl_
+
+touch k || framework_failure_
+setfacl -m user::r-- k || framework_failure_
+ln -s k s || framework_failure_
+
+set _ $(ls -Log s); shift; link=$1
+set _ $(ls -og k); shift; reg=$1
+
+test "$link" = "$reg" || fail=1
+
+Exit $fail
diff --git a/tests/ls/sort-width-option.sh b/tests/ls/sort-width-option.sh
new file mode 100755
index 0000000..3ab0f69
--- /dev/null
+++ b/tests/ls/sort-width-option.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+# Exercise the --sort=width option.
+
+# Copyright (C) 2021-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_ ls
+
+mkdir subdir || framework_failure_
+touch subdir/aaaaa || framework_failure_
+touch subdir/bbb || framework_failure_
+touch subdir/cccc || framework_failure_
+touch subdir/d || framework_failure_
+touch subdir/zz || framework_failure_
+
+
+ls --sort=width subdir > out || fail=1
+cat <<\EOF > exp || framework_failure_
+d
+zz
+bbb
+cccc
+aaaaa
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/ls/stat-dtype.sh b/tests/ls/stat-dtype.sh
new file mode 100755
index 0000000..f500358
--- /dev/null
+++ b/tests/ls/stat-dtype.sh
@@ -0,0 +1,60 @@
+#!/bin/sh
+# Ensure that ls --file-type does not call stat unnecessarily.
+# Also check for the dtype-related (and fs-type dependent) bug
+# in coreutils-6.0 that made ls -CF columns misaligned.
+
+# Copyright (C) 2006-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/>.
+
+# The trick is to create an un-stat'able symlink and to see if ls
+# can report its type nonetheless, using dirent.d_type.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+
+# Skip this test unless "." is on a file system with useful d_type info.
+# FIXME: This uses "ls -p" to decide whether to test "ls" with other options,
+# but if ls's d_type code is buggy then "ls -p" might be buggy too.
+mkdir -p c/d || framework_failure_
+chmod a-x c || framework_failure_
+if test "X$(ls -p c 2>&1)" != Xd/; then
+ skip_ "'.' is not on a suitable file system for this test"
+fi
+
+mkdir d || framework_failure_
+ln -s / d/s || framework_failure_
+chmod 600 d || framework_failure_
+
+mkdir -p e/a2345 e/b || framework_failure_
+chmod 600 e || framework_failure_
+
+
+ls --file-type d > out || fail=1
+cat <<\EOF > exp || framework_failure_
+s@
+EOF
+
+compare exp out || fail=1
+
+# Check for the ls -CF misaligned-columns bug:
+ls -CF e > out || fail=1
+
+# coreutils-6.0 would print two spaces after the first slash,
+# rather than the appropriate TAB.
+printf 'a2345/\tb/\n' > exp || framework_failure_
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/ls/stat-failed.sh b/tests/ls/stat-failed.sh
new file mode 100755
index 0000000..d7bbed5
--- /dev/null
+++ b/tests/ls/stat-failed.sh
@@ -0,0 +1,57 @@
+#!/bin/sh
+# Verify that ls works properly when it fails to stat a file that is
+# not mentioned on the command line.
+
+# Copyright (C) 2006-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_ ls
+skip_if_root_
+
+LS_MINOR_PROBLEM=1
+
+mkdir d || framework_failure_
+ln -s / d/s || framework_failure_
+chmod 600 d || framework_failure_
+
+
+returns_ 1 ls -Log d > out || fail=1
+
+# Linux 2.6.32 client with Isilon OneFS always returns d_type==DT_DIR ('d')
+# Newer Linux 3.10.0 returns the more correct DT_UNKNOWN ('?')
+grep '^[l?]?' out || skip_ 'unrecognized d_type returned'
+
+cat <<\EOF > exp || framework_failure_
+total 0
+?????????? ? ? ? s
+EOF
+
+sed 's/^l/?/' out | compare exp - || fail=1
+
+# Ensure that the offsets in --dired output are accurate.
+rm -f out exp
+returns_ $LS_MINOR_PROBLEM ls --dired -l d > out || fail=1
+
+cat <<\EOF > exp || framework_failure_
+ total 0
+ ?????????? ? ? ? ? ? s
+//DIRED// 44 45
+//DIRED-OPTIONS// --quoting-style=literal
+EOF
+
+sed 's/^ l/ ?/' out | compare exp - || fail=1
+
+Exit $fail
diff --git a/tests/ls/stat-free-color.sh b/tests/ls/stat-free-color.sh
new file mode 100755
index 0000000..c007876
--- /dev/null
+++ b/tests/ls/stat-free-color.sh
@@ -0,0 +1,88 @@
+#!/bin/sh
+# Show that --color need not use stat, as long as we have d_type support.
+
+# 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_ ls
+require_strace_ stat
+require_dirent_d_type_
+
+stats='stat'
+# List of other _file name_ stat functions to increase coverage.
+other_stats='statx lstat stat64 lstat64 newfstatat fstatat64'
+for stat in $other_stats; do
+ strace -qe "$stat" true > /dev/null 2>&1 &&
+ stats="$stats,$stat"
+done
+
+# Disable enough features via LS_COLORS so that ls --color
+# can do its job without calling stat (other than the obligatory
+# one-call-per-command-line argument).
+cat <<EOF > color-without-stat || framework_failure_
+RESET 0
+DIR 01;34
+LINK 01;36
+FIFO 40;33
+SOCK 01;35
+DOOR 01;35
+BLK 40;33;01
+CHR 40;33;01
+ORPHAN 00
+SETUID 00
+SETGID 00
+CAPABILITY 00
+STICKY_OTHER_WRITABLE 00
+OTHER_WRITABLE 00
+STICKY 00
+EXEC 00
+MULTIHARDLINK 00
+EOF
+eval $(dircolors -b color-without-stat)
+
+# The system may perform additional stat-like calls before main.
+# Furthermore, underlying library functions may also implicitly
+# add an extra stat call, e.g. opendir since glibc-2.21-360-g46f894d.
+# Finally, ls(1) makes a stat call for stdout, but only in the case
+# when there is something to output.
+# To get the comparison right, first get a baseline count for running
+# 'ls -a' with one empty directory argument. Then, compare that with
+# the invocation under test.
+mkdir d || framework_failure_
+
+strace -q -o log1 -e $stats ls -a --color=always d || fail=1
+n_stat1=$(grep -vF '+++' log1 | wc -l) || framework_failure_
+
+test $n_stat1 = 0 \
+ && skip_ 'No stat calls recognized on this platform'
+
+# Populate the test directory.
+mkdir d/subdir \
+ && touch d/regf \
+ && ln d/regf d/hlink \
+ && ln -s regf d/slink \
+ && ln -s nowhere d/dangle \
+ || framework_failure_
+
+# Invocation under test.
+strace -q -o log2 -e $stats ls --color=always d || fail=1
+n_stat2=$(grep -vF '+++' log2 | wc -l) || framework_failure_
+
+# Expect the same number of stat calls.
+test $n_stat1 = $n_stat2 \
+ || { fail=1; head -n30 log*; }
+
+Exit $fail
diff --git a/tests/ls/stat-free-symlinks.sh b/tests/ls/stat-free-symlinks.sh
new file mode 100755
index 0000000..706d415
--- /dev/null
+++ b/tests/ls/stat-free-symlinks.sh
@@ -0,0 +1,75 @@
+#!/bin/sh
+# ensure that ls does not stat a symlink in an unusual case
+
+# Copyright (C) 2007-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_ ls
+require_strace_ stat
+
+stats='stat'
+# List of other _file name_ stat functions to increase coverage.
+other_stats='statx lstat stat64 lstat64 newfstatat fstatat64'
+for stat in $other_stats; do
+ strace -qe "$stat" true > /dev/null 2>&1 &&
+ stats="$stats,$stat"
+done
+
+# The system may perform additional stat-like calls before main.
+# Furthermore, underlying library functions may also implicitly
+# add an extra stat call, e.g. opendir since glibc-2.21-360-g46f894d.
+# To avoid counting those, first get a baseline count for running
+# ls with one empty directory argument. Then, compare that with the
+# invocation under test.
+mkdir d || framework_failure_
+strace -q -o log1 -e $stats ls -F --color=always d || fail=1
+n_stat1=$(grep -vF '+++' log1 | wc -l) || framework_failure_
+
+test $n_stat1 = 0 \
+ && skip_ 'No stat calls recognized on this platform'
+
+
+touch x || framework_failure_
+chmod a+x x || framework_failure_
+ln -s x link-to-x || framework_failure_
+
+
+# ls from coreutils 6.9 would unnecessarily stat a symlink in an unusual case:
+# When not coloring orphan and missing entries, and without ln=target,
+# ensure that ls -F (or -d, or -l: i.e., when not dereferencing)
+# does not stat a symlink to directory, and does still color that
+# symlink and an executable file properly.
+
+LS_COLORS='or=0:mi=0:ex=01;32:ln=01;35' \
+ strace -qe $stats -o log2 ls -F --color=always x link-to-x > out.tmp || fail=1
+n_stat2=$(grep -vF '+++' log2 | wc -l) || framework_failure_
+
+# Expect one more stat call,
+# which failed with coreutils 6.9 and earlier, which had 2.
+test $n_stat1 = $(($n_stat2 - 1)) \
+ || { fail=1; head -n30 log*; }
+
+# Check that output is colored, as requested, too.
+{
+ printf '\033[0m\033[01;35mlink-to-x\033[0m@\n'
+ printf '\033[01;32mx\033[0m*\n'
+} > exp || fail=1
+# Elide info messages strace can send to stdout of the form:
+# [ Process PID=1234 runs in 32 bit mode. ]
+sed '/Process PID=/d' out.tmp > out
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/ls/stat-vs-dirent.sh b/tests/ls/stat-vs-dirent.sh
new file mode 100755
index 0000000..08ec486
--- /dev/null
+++ b/tests/ls/stat-vs-dirent.sh
@@ -0,0 +1,60 @@
+#!/bin/sh
+# Ensure that d_ino (from ls -di) and st_ino (from stat --format=%i) match.
+
+# Copyright (C) 2006-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_ ls
+
+
+root_dev_ino=$(stat --format=%d-%i /)
+t=$(pwd)
+while :; do
+ if ls -i1 "$t" > tmp; then
+ # Extract the inode number from the first line of output from ls -i1.
+ # This value comes from dirent.d_ino, on systems with d_ino support.
+ d_ino=$(sed -n '1s/^ *\([0-9][0-9]*\) .*/\1/p;q' tmp)
+
+ # Extract the name of the corresponding directory entry.
+ file=$(sed -n '1s/^ *[0-9][0-9]* //p;q' tmp)
+
+ # Get its inode number (stat.st_ino) via stat(1)'s call to lstat.
+ st_ino=$(stat --format=%i "$t/$file") ||
+ skip_ "error stating: $t/$file" # removed or newlines in name etc.
+
+ # Make sure that they are the same.
+ # We know from experience that there may be mismatches on some
+ # buggy file systems, at mount points.
+ # 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,
+ so you should report it to your operating system vendor." 1>&2
+
+ fail=1
+ break
+ fi
+ fi
+
+ t=$(cd "$t/.."; pwd)
+ dev_ino=$(stat --format=%d-%i "$t")
+ test $dev_ino = $root_dev_ino && break
+done
+
+Exit $fail
diff --git a/tests/ls/symlink-quote.sh b/tests/ls/symlink-quote.sh
new file mode 100755
index 0000000..688b9a4
--- /dev/null
+++ b/tests/ls/symlink-quote.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+# Ensure symlinks are quoted appropriately
+
+# 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_ ls
+
+ln -s 'needs quoting' symlink || framework_failure_
+
+ls -l --quoting-style='shell-escape' symlink >out || fail=1
+
+# Coreutils v8.26 and 8.27 failed to quote the target name
+grep -q "symlink -> 'needs quoting'\$" out ||
+ { cat out; fail=1; }
+
+Exit $fail
diff --git a/tests/ls/symlink-slash.sh b/tests/ls/symlink-slash.sh
new file mode 100755
index 0000000..ba3c6a5
--- /dev/null
+++ b/tests/ls/symlink-slash.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+# Do dereference a symlink arg if its name is written with a trailing slash.
+
+# 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_ ls
+
+mkdir dir || framework_failure_
+ln -s dir symlink || framework_failure_
+
+set $(ls -l symlink/)
+
+# Prior to fileutils-4.0k, the following would have output '... symlink -> dir'.
+test "$*" = 'total 0' && : || fail=1
+
+Exit $fail
diff --git a/tests/ls/time-style-diag.sh b/tests/ls/time-style-diag.sh
new file mode 100755
index 0000000..2e6817e
--- /dev/null
+++ b/tests/ls/time-style-diag.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+# Ensure that an invalid --time-style=ARG is diagnosed the way we want.
+
+# 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_ ls
+
+returns_ 2 ls -l --time-style=XX > out 2> err || fail=1
+
+cat <<\EOF > exp || framework_failure_
+ls: invalid argument 'XX' for 'time style'
+Valid arguments are:
+ - [posix-]full-iso
+ - [posix-]long-iso
+ - [posix-]iso
+ - [posix-]locale
+ - +FORMAT (e.g., +%H:%M) for a 'date'-style format
+Try 'ls --help' for more information.
+EOF
+
+compare exp err || fail=1
+compare /dev/null out || fail=1
+
+Exit $fail
diff --git a/tests/ls/w-option.sh b/tests/ls/w-option.sh
new file mode 100755
index 0000000..81aaf48
--- /dev/null
+++ b/tests/ls/w-option.sh
@@ -0,0 +1,48 @@
+#!/bin/sh
+# exercise the -w option
+
+# Copyright (C) 2015-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_ ls
+getlimits_
+
+touch a b || framework_failure_
+chmod a+x a || framework_failure_
+
+# Negative values disallowed
+returns_ 2 ls -w-1 || fail=1
+
+# Verify octal parsing (especially since 0 is allowed)
+returns_ 2 ls -w08 || fail=1
+
+# Overflowed values are capped at SIZE_MAX
+ls -w$SIZE_OFLOW || fail=1
+
+# After coreutils 8.24 -w0 means no limit
+# and delimiting with spaces
+ls -w0 -x -T1 a b > out || fail=1
+printf '%s\n' 'a b' > exp || framework_failure_
+compare exp out || fail=1
+
+# Ensure that 0 line length doesn't cause division by zero
+TERM=xterm ls -w0 -x --color=always || fail=1
+
+# coreutils <= 8.24 could display 1 column too few
+ls -w4 -x -T0 a b > out || fail=1
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/ls/x-option.sh b/tests/ls/x-option.sh
new file mode 100755
index 0000000..6e232b1
--- /dev/null
+++ b/tests/ls/x-option.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+# Exercise the -x option.
+
+# Copyright (C) 2007-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_ ls
+
+mkdir subdir || framework_failure_
+touch subdir/b || framework_failure_
+touch subdir/a || framework_failure_
+
+
+# Coreutils 6.8 and 6.9 would output this in the wrong order.
+ls -x subdir > out || fail=1
+ls -rx subdir >> out || fail=1
+cat <<\EOF > exp || framework_failure_
+a b
+b a
+EOF
+
+compare exp out || fail=1
+
+Exit $fail
diff --git a/tests/ls/zero-option.sh b/tests/ls/zero-option.sh
new file mode 100755
index 0000000..28205e1
--- /dev/null
+++ b/tests/ls/zero-option.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+# Verify behavior of ls --zero.
+
+# Copyright 2021-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_ ls
+
+mkdir dir && touch dir/a dir/b dir/cc || framework_failure_
+
+allowed_options='-l' # explict -l with --zero is allowed
+LC_ALL=C ls $allowed_options --zero dir >out || fail=1
+grep '^total' out || fail=1 # Ensure -l honored
+
+disallowed_options='-l --dired' # dired only enabled with -l
+returns_ 2 ls $disallowed_options --zero dir || fail=1
+
+disabled_options='--color=always -x -m -C -Q -q'
+LC_ALL=C ls $disabled_options --zero dir >out || fail=1
+tr '\n' '\0' <<EOF >exp
+a
+b
+cc
+EOF
+
+compare exp out || fail=1
+
+Exit $fail