123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727 |
- # This file is sourced by init.sh, *before* its initialization.
- # Copyright (C) 2010-2018 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/>.
- # This goes hand in hand with the "exec 9>&2;" in tests/Makefile.am's
- # TESTS_ENVIRONMENT definition.
- stderr_fileno_=9
- # Having an unsearchable directory in PATH causes execve to fail with EACCES
- # when applied to an unresolvable program name, contrary to the desired ENOENT.
- # Avoid the problem by rewriting PATH to exclude unsearchable directories.
- # Also, if PATH lacks /sbin and/or /usr/sbin, append it/them.
- sanitize_path_()
- {
- # FIXME: remove double quotes around $IFS when all tests use init.sh.
- # They constitute a work-around for a bug in FreeBSD 8.1's /bin/sh.
- local saved_IFS="$IFS"
- IFS=:
- set -- $PATH
- IFS=$saved_IFS
- local d d1
- local colon=
- local new_path=
- for d in "$@"; do
- test -z "$d" && d1=. || d1=$d
- if ls -d "$d1/." > /dev/null 2>&1; then
- new_path="$new_path$colon$d"
- colon=':'
- fi
- done
- for d in /sbin /usr/sbin ; do
- case ":$new_path:" in
- *:$d:*) ;;
- *) new_path="$new_path:$d" ;;
- esac
- done
- PATH=$new_path
- export PATH
- }
- getlimits_()
- {
- eval $(getlimits)
- test "$INT_MAX" || fatal_ "running getlimits"
- }
- require_no_default_acl_()
- {
- if getfacl --version < /dev/null > /dev/null 2>&1; then
- getfacl "$1" | grep '^default:' && skip_ 'Default ACL detected'
- else
- ls -ld "$1" | grep '.........+' && skip_ 'ACL detected'
- fi
- }
- require_acl_()
- {
- getfacl --version < /dev/null > /dev/null 2>&1 \
- && setfacl --version < /dev/null > /dev/null 2>&1 \
- || skip_ "This test requires getfacl and setfacl."
- id -u bin > /dev/null 2>&1 \
- || skip_ "This test requires a local user named bin."
- }
- is_local_dir_()
- {
- test $# = 1 || framework_failure_
- df --local "$1" >/dev/null 2>&1
- }
- require_mount_list_()
- {
- local mount_list_fail='cannot read table of mounted file systems'
- df --local 2>&1 | grep -F "$mount_list_fail" >/dev/null &&
- skip_ "$mount_list_fail"
- }
- dump_mount_list_()
- {
- cat /proc/self/mountinfo ||
- cat /proc/self/mounts ||
- cat /proc/mounts ||
- cat /etc/mtab
- }
- require_local_dir_()
- {
- require_mount_list_
- is_local_dir_ . ||
- skip_ "This test must be run on a local file system."
- }
- require_selinux_()
- {
- # When in a chroot of an SELinux-enabled system, but with a mock-simulated
- # SELinux-*disabled* system, recognize that SELinux is disabled system wide:
- grep 'selinuxfs$' /proc/filesystems > /dev/null \
- || skip_ "this system lacks SELinux support"
- # Independent of whether SELinux is enabled system-wide,
- # the current file system may lack SELinux support.
- # Also the current build may have SELinux support disabled.
- case $(ls -Zd .) in
- '? .'|'unlabeled .')
- test -z "$CONFIG_HEADER" \
- && framework_failure_ 'CONFIG_HEADER not defined'
- grep '^#define HAVE_SELINUX_SELINUX_H 1' "$CONFIG_HEADER" > /dev/null \
- && selinux_missing_="(file) system" || selinux_missing_="build"
- skip_ "this $selinux_missing_ lacks SELinux support"
- ;;
- esac
- }
- # Return the SELinux type component if available
- get_selinux_type() { ls -Zd "$1" | sed -n 's/.*:\(.*_t\)[: ].*/\1/p'; }
- # Whether SELinux Multi Level Security is enabled
- mls_enabled_() {
- sestatus 2>&1 |
- grep 'Policy MLS status:.*enabled' > /dev/null
- }
- # Skip this test if we're not in SELinux "enforcing" mode.
- require_selinux_enforcing_()
- {
- require_selinux_
- test "$(getenforce)" = Enforcing \
- || skip_ "This test is useful only with SELinux in Enforcing mode."
- }
- require_smack_()
- {
- grep 'smackfs$' /proc/filesystems > /dev/null \
- || skip_ "this system lacks SMACK support"
- test "$(ls -Zd .)" != '? .' \
- || skip_ "this file system lacks SMACK support"
- }
- require_openat_support_()
- {
- # Skip this test if your system has neither the openat-style functions
- # nor /proc/self/fd support with which to emulate them.
- test -z "$CONFIG_HEADER" \
- && framework_failure_ 'CONFIG_HEADER not defined'
- _skip=yes
- grep '^#define HAVE_OPENAT' "$CONFIG_HEADER" > /dev/null && _skip=no
- test -d /proc/self/fd && _skip=no
- if test $_skip = yes; then
- skip_ 'this system lacks openat support'
- fi
- }
- # Return true if command runs with the
- # ulimit specified in the first argument
- ulimit_supported_()
- {
- local v
- v="$1"
- shift
- (
- # Try to disable core dumps which may
- # occur with memory constraints
- trap '' SEGV; ulimit -c 0;
- ulimit -v $v && "$@"
- ) >/dev/null 2>&1
- }
- # Determine the minimum required VM limit to run the given command.
- # Output that value to stdout ... to be used by the caller.
- # Return 0 in case of success, and a non-Zero value otherwise.
- get_min_ulimit_v_()
- {
- local v
- local page_size
- # Increase result by this amount to avoid alignment issues
- page_size=$(getconf PAGESIZE || echo 4096)
- page_size=$(($page_size / 1024))
- for v in $( seq 5000 5000 50000 ); do
- if ulimit_supported_ $v "$@"; then
- local prev_v
- prev_v=$v
- for v in $( seq $(($prev_v-1000)) -1000 1000 ); do
- ulimit_supported_ $v "$@" ||
- {
- ret_v=$((prev_v + $page_size))
- echo $ret_v
- return 0
- }
- prev_v=$v
- done
- fi
- done
- # The above did not find a working limit. Echo a very small number - just
- # in case the caller does not handle the non-Zero return value.
- echo 1; return 1
- }
- require_readable_root_()
- {
- test -r / || skip_ "/ is not readable"
- }
- # Skip the current test if strace is not available or doesn't work
- # with the named syscall. Usage: require_strace_ unlink
- require_strace_()
- {
- test $# = 1 || framework_failure_
- strace -V < /dev/null > /dev/null 2>&1 ||
- skip_ 'no strace program'
- strace -qe "$1" echo > /dev/null 2>&1 ||
- skip_ 'strace -qe "'"$1"'" does not work'
- # On some linux/sparc64 systems, strace works fine on 32-bit executables,
- # but prints only one line of output for every 64-bit executable.
- strace -o log-help ls --help >/dev/null || framework_failure_
- n_lines_help=$(wc -l < log-help)
- rm -f log-help
- if test $n_lines_help = 0 || test $n_lines_help = 1; then
- skip_ 'strace produces no more than one line of output'
- fi
- }
- # Skip the current test if valgrind doesn't work,
- # which could happen if not installed,
- # or hasn't support for the built architecture,
- # or hasn't appropriate error suppressions installed etc.
- require_valgrind_()
- {
- valgrind --error-exitcode=1 true 2>/dev/null ||
- skip_ "requires a working valgrind"
- }
- # Skip the current test if setfacl doesn't work on the current file system,
- # which could happen if not installed, or if ACLs are not supported by the
- # kernel or the file system, or are turned off via mount options.
- #
- # Work around the following two issues:
- #
- # 1) setfacl maps ACLs into file permission bits if on "noacl" file systems.
- #
- # On file systems which do not support ACLs (e.g. ext4 mounted with -o noacl),
- # setfacl operates on the regular file permission bits, and only fails if the
- # given ACL spec does not fit into there. Thus, to test if ACLs really work
- # on the current file system, pass an ACL spec which can't be mapped that way.
- # "Default" ACLs (-d) seem to fulfill this requirement.
- #
- # 2) setfacl only invokes the underlying system call if the ACL would change.
- #
- # If the given ACL spec would not change the ACLs on the file, then setfacl
- # does not invoke the underlying system call - setxattr(). Therefore, to test
- # if setting ACLs really works on the current file system, call setfacl twice
- # with conflictive ACL specs.
- require_setfacl_()
- {
- local d='acltestdir_'
- mkdir $d || framework_failure_
- local f=0
- setfacl -d -m user::r-x $d \
- && setfacl -d -m user::rwx $d \
- || f=1
- rm -rf $d || framework_failure_
- test $f = 0 \
- || skip_ "setfacl does not work on the current file system"
- }
- # Require a controlling input 'terminal'.
- require_controlling_input_terminal_()
- {
- have_input_tty=yes
- tty -s || have_input_tty=no
- test -t 0 || have_input_tty=no
- if test "$have_input_tty" = no; then
- skip_ 'requires controlling input terminal
- This test must have a controlling input "terminal", so it may not be
- run via "batch", "at", or "ssh". On some systems, it may not even be
- run in the background.'
- fi
- }
- require_built_()
- {
- skip_=no
- for i in "$@"; do
- case " $built_programs " in
- *" $i "*) ;;
- *) echo "$i: not built" 1>&2; skip_=yes ;;
- esac
- done
- test $skip_ = yes && skip_ "required program(s) not built"
- }
- require_file_system_bytes_free_()
- {
- local req=$1
- local expr=$(stat -f --printf "$req / %S <= %a" .)
- $AWK "BEGIN{ exit !($expr) }" \
- || skip_ "this test needs at least $req bytes of free space"
- }
- uid_is_privileged_()
- {
- # Make sure id -u succeeds.
- my_uid=$(id -u) \
- || { echo "$0: cannot run 'id -u'" 1>&2; return 1; }
- # Make sure it gives valid output.
- case $my_uid in
- 0) ;;
- *[!0-9]*)
- echo "$0: invalid output ('$my_uid') from 'id -u'" 1>&2
- return 1 ;;
- *) return 1 ;;
- esac
- }
- get_process_status_()
- {
- sed -n '/^State:[ ]*\([[:alpha:]]\).*/s//\1/p' /proc/$1/status
- }
- # Convert an ls-style permission string, like drwxr----x and -rw-r-x-wx
- # to the equivalent chmod --mode (-m) argument, (=,u=rwx,g=r,o=x and
- # =,u=rw,g=rx,o=wx). Ignore ACLs.
- rwx_to_mode_()
- {
- case $# in
- 1) rwx=$1;;
- *) echo "$0: wrong number of arguments" 1>&2
- echo "Usage: $0 ls-style-mode-string" 1>&2
- return;;
- esac
- case $rwx in
- [ld-][rwx-][rwx-][rwxsS-][rwx-][rwx-][rwxsS-][rwx-][rwx-][rwxtT-]) ;;
- [ld-][rwx-][rwx-][rwxsS-][rwx-][rwx-][rwxsS-][rwx-][rwx-][rwxtT-][+.]) ;;
- *) echo "$0: invalid mode string: $rwx" 1>&2; return;;
- esac
- # Perform these conversions:
- # S s
- # s xs
- # T t
- # t xt
- # The 'T' and 't' ones are only valid for 'other'.
- s='s/S/@/;s/s/x@/;s/@/s/'
- t='s/T/@/;s/t/x@/;s/@/t/'
- u=$(echo $rwx|sed 's/^.\(...\).*/,u=\1/;s/-//g;s/^,u=$//;'$s)
- g=$(echo $rwx|sed 's/^....\(...\).*/,g=\1/;s/-//g;s/^,g=$//;'$s)
- o=$(echo $rwx|sed 's/^.......\(...\).*/,o=\1/;s/-//g;s/^,o=$//;'$s';'$t)
- echo "=$u$g$o"
- }
- # Set the global variable stty_reversible_ to a space-separated list of the
- # reversible settings from stty.c. stty_reversible_ also starts and ends
- # with a space.
- stty_reversible_init_()
- {
- # Pad start with one space for the first option to match in query function.
- stty_reversible_=' '$(perl -lne '/^ *{"(.*?)",.*\bREV\b/ and print $1' \
- "$abs_top_srcdir"/src/stty.c | tr '\n' ' ')
- # Ensure that there are at least 62, i.e., so we're alerted if
- # reformatting the source empties the list.
- test 62 -le $(echo "$stty_reversible_"|wc -w) \
- || framework_failure_ "too few reversible settings"
- }
- # Test whether $1 is one of stty's reversible options.
- stty_reversible_query_()
- {
- case $stty_reversible_ in
- '')
- framework_failure_ "stty_reversible_init_() not called?";;
- *" $1 "*)
- return 0;;
- *)
- return 1;;
- esac
- }
- skip_if_()
- {
- case $1 in
- root) skip_ must be run as root ;;
- non-root) skip_ must be run as non-root ;;
- *) ;; # FIXME?
- esac
- }
- very_expensive_()
- {
- if test "$RUN_VERY_EXPENSIVE_TESTS" != yes; then
- skip_ 'very expensive: disabled by default
- This test is very expensive, so it is disabled by default.
- To run it anyway, rerun make check with the RUN_VERY_EXPENSIVE_TESTS
- environment variable set to yes. E.g.,
- env RUN_VERY_EXPENSIVE_TESTS=yes make check
- or use the shortcut target of the toplevel Makefile,
- make check-very-expensive
- '
- fi
- }
- expensive_()
- {
- if test "$RUN_EXPENSIVE_TESTS" != yes; then
- skip_ 'expensive: disabled by default
- This test is relatively expensive, so it is disabled by default.
- To run it anyway, rerun make check with the RUN_EXPENSIVE_TESTS
- environment variable set to yes. E.g.,
- env RUN_EXPENSIVE_TESTS=yes make check
- or use the shortcut target of the toplevel Makefile,
- make check-expensive
- '
- fi
- }
- # Test whether we can run our just-built root owned rm,
- # i.e., that $NON_ROOT_USERNAME has access to the build directory.
- nonroot_has_perm_()
- {
- require_built_ chroot
- local rm_version=$(
- chroot --skip-chdir --user=$NON_ROOT_USERNAME / env PATH="$PATH" \
- rm --version |
- sed -n '1s/.* //p'
- )
- case ":$rm_version:" in
- :$PACKAGE_VERSION:) ;;
- *) return 1;;
- esac
- }
- require_root_()
- {
- uid_is_privileged_ || skip_ "must be run as root"
- NON_ROOT_USERNAME=${NON_ROOT_USERNAME=nobody}
- NON_ROOT_GID=${NON_ROOT_GID=$(id -g $NON_ROOT_USERNAME)}
- # When the current test invokes chroot, call nonroot_has_perm_
- # to check for a common problem.
- grep '^[ ]*chroot' "../$0" \
- && { nonroot_has_perm_ \
- || skip_ "user $NON_ROOT_USERNAME lacks execute permissions"; }
- }
- skip_if_root_() { uid_is_privileged_ && skip_ "must be run as non-root"; }
- # Set 'groups' to a space-separated list of at least two groups
- # of which the user is a member.
- require_membership_in_two_groups_()
- {
- test $# = 0 || framework_failure_
- groups=${COREUTILS_GROUPS-$( (id -G || /usr/xpg4/bin/id -G) 2>/dev/null)}
- case "$groups" in
- *' '*) ;;
- *) skip_ 'requires membership in two groups
- this test requires that you be a member of more than one group,
- but running '\''id -G'\'' either failed or found just one. If you really
- are a member of at least two groups, then rerun this test with
- COREUTILS_GROUPS set in your environment to the space-separated list
- of group names or numbers. E.g.,
- env COREUTILS_GROUPS='\''users cdrom'\'' make check
- '
- ;;
- esac
- }
- # Is /proc/$PID/status supported?
- require_proc_pid_status_()
- {
- sleep 2 &
- local pid=$!
- sleep .5
- grep '^State:[ ]*[S]' /proc/$pid/status > /dev/null 2>&1 ||
- skip_ "/proc/$pid/status: missing or 'different'"
- kill $pid
- }
- # Does trap support signal names?
- # Old versions of ash did not.
- require_trap_signame_()
- {
- (trap '' CHLD) || skip_ 'requires trap with signal name support'
- }
- # Does kill support sending signal to whole group?
- # dash 0.5.8 at least does not.
- require_kill_group_()
- {
- kill -0 -- -1 || skip_ 'requires kill with group signalling support'
- }
- # Return nonzero if the specified path is on a file system for
- # which FIEMAP support exists. Note some file systems (like ext3 and btrfs)
- # only support FIEMAP for files, not directories.
- fiemap_capable_()
- {
- if ! python < /dev/null; then
- warn_ 'fiemap_capable_: python missing: assuming not fiemap capable'
- return 1
- fi
- python "$abs_srcdir"/tests/fiemap-capable "$@"
- }
- # Skip the current test if "." lacks d_type support.
- require_dirent_d_type_()
- {
- python < /dev/null \
- || skip_ python missing: assuming no d_type support
- python "$abs_srcdir"/tests/d_type-check \
- || skip_ requires d_type support
- }
- # Skip the current test if we lack Perl.
- require_perl_()
- {
- : ${PERL=perl}
- $PERL -e 'use warnings' > /dev/null 2>&1 \
- || skip_ 'configure did not find a usable version of Perl'
- }
- # Does the current (working-dir) file system support sparse files?
- require_sparse_support_()
- {
- test $# = 0 || framework_failure_
- # Test whether we can create a sparse file.
- # For example, on Darwin6.5 with a file system of type hfs, it's not possible.
- # NTFS requires 128K before a hole appears in a sparse file.
- t=sparse.$$
- dd bs=1 seek=128K of=$t < /dev/null 2> /dev/null
- set x $(du -sk $t)
- kb_size=$2
- rm -f $t
- if test $kb_size -ge 128; then
- skip_ 'this file system does not support sparse files'
- fi
- }
- # Compile a shared lib using the GCC options for doing so.
- # Pass input and output file as parameters respectively.
- # Any other optional parmeters are passed to $CC.
- gcc_shared_()
- {
- local in=$1
- local out=$2
- shift 2 || return 1
- $CC -Wall -shared --std=gnu99 -fPIC -O2 $* "$in" -o "$out" -ldl
- }
- # There are a myriad of ways to build shared libs,
- # so we only consider running tests requiring shared libs,
- # on platforms that support building them as follows.
- require_gcc_shared_()
- {
- gcc_shared_ '-' 'd.so' -xc < /dev/null 2>&1 \
- || skip_ '$CC -shared ... failed to build a shared lib'
- rm -f d.so
- }
- mkfifo_or_skip_()
- {
- test $# = 1 || framework_failure_
- if ! mkfifo "$1"; then
- # Make an exception of this case -- usually we interpret framework-creation
- # failure as a test failure. However, in this case, when running on a SunOS
- # system using a disk NFS mounted from OpenBSD, the above fails like this:
- # mkfifo: cannot make fifo 'fifo-10558': Not owner
- skip_ 'unable to create a fifo'
- fi
- }
- # Disable the current test if the working directory seems to have
- # the setgid bit set.
- skip_if_setgid_()
- {
- setgid_tmpdir=setgid-$$
- (umask 77; mkdir $setgid_tmpdir)
- perms=$(stat --printf %A $setgid_tmpdir)
- rmdir $setgid_tmpdir
- case $perms in
- drwx------);;
- drwxr-xr-x);; # Windows98 + DJGPP 2.03
- *) skip_ 'this directory has the setgid bit set';;
- esac
- }
- # Skip if files are created with a different group to the current user
- # This can happen due to a setgid dir, or by some other mechanism on OS X:
- # https://unix.stackexchange.com/q/63865
- # https://bugs.gnu.org/14024#41
- skip_if_nondefault_group_()
- {
- touch grp.$$
- gen_ug=$(stat -c '%u:%g' grp.$$)
- rm grp.$$
- test "$gen_ug" = "$(id -ru):$(id -rg)" ||
- skip_ 'Files are created with a different gid'
- }
- skip_if_mcstransd_is_running_()
- {
- test $# = 0 || framework_failure_
- # When mcstransd is running, you'll see only the 3-component
- # version of file-system context strings. Detect that,
- # and if it's running, skip this test.
- __ctx=$(stat --printf='%C\n' .) || framework_failure_
- case $__ctx in
- *:*:*:*) __ctx_ok=1 ;; # four components is ok
- *:*:*) # three components is ok too if there is no MLS
- mls_enabled_ || __ctx_ok=1 ;;
- esac
- test "$__ctx_ok" ||
- skip_ "unexpected context '$__ctx'; turn off mcstransd"
- }
- # Skip the current test if umask doesn't work as usual.
- # This test should be run in the temporary directory that ends
- # up being removed via the trap commands.
- working_umask_or_skip_()
- {
- umask 022
- touch file1 file2
- chmod 644 file2
- perms=$(ls -l file1 file2 | sed 's/ .*//' | uniq)
- rm -f file1 file2
- case $perms in
- *'
- '*) skip_ 'your build directory has unusual umask semantics'
- esac
- }
- # Retry a function requiring a sufficient delay to _pass_
- # using a truncated exponential backoff method.
- # Example: retry_delay_ dd_reblock_1 .1 6
- # This example will call the dd_reblock_1 function with
- # an initial delay of .1 second and call it at most 6 times
- # with a max delay of 3.2s (doubled each time), or a total of 6.3s
- # Note ensure you do _not_ quote the parameter to GNU sleep in
- # your function, as it may contain separate values that sleep
- # needs to accumulate.
- # Further function arguments will be forwarded to the test function.
- retry_delay_()
- {
- local test_func=$1
- local init_delay=$2
- local max_n_tries=$3
- shift 3 || return 1
- local attempt=1
- local num_sleeps=$attempt
- local time_fail
- while test $attempt -le $max_n_tries; do
- local delay=$($AWK -v n=$num_sleeps -v s="$init_delay" \
- 'BEGIN { print s * n }')
- "$test_func" "$delay" "$@" && { time_fail=0; break; } || time_fail=1
- attempt=$(expr $attempt + 1)
- num_sleeps=$(expr $num_sleeps '*' 2)
- done
- test "$time_fail" = 0
- }
- # Call this with a list of programs under test immediately after
- # sourcing init.sh.
- print_ver_()
- {
- require_built_ "$@"
- if test "$VERBOSE" = yes; then
- local i
- for i in $*; do
- env $i --version
- done
- fi
- }
- # Are we running on GNU/Hurd?
- require_gnu_()
- {
- test "$(uname)" = GNU \
- || skip_ 'not running on GNU/Hurd'
- }
- sanitize_path_
|