| |
|
|
| |
|
|
| |
| |
| |
| |
|
|
| |
| |
| |
| |
|
|
| |
| |
|
|
| |
| |
| stderr_fileno_=9 |
|
|
| |
| |
| |
| |
| sanitize_path_() |
| { |
| |
| |
| 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_() |
| { |
| |
| |
| grep 'selinuxfs$' /proc/filesystems > /dev/null \ |
| || skip_ "this system lacks SELinux support" |
|
|
| |
| |
| |
| 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 |
| } |
|
|
| |
| get_selinux_type() { ls -Zd "$1" | sed -n 's/.*:\(.*_t\)[: ].*/\1/p'; } |
|
|
| |
| mls_enabled_() { |
| sestatus 2>&1 | |
| grep 'Policy MLS status:.*enabled' > /dev/null |
| } |
|
|
| |
| 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_() |
| { |
| |
| |
|
|
| 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 |
| } |
|
|
| |
| |
| ulimit_supported_() |
| { |
| local v |
| v="$1" |
| shift |
|
|
| local ulimit_start_=$(date +%s) || skip_ 'ulimit: date error' |
|
|
| ( |
| |
| |
| trap '' SEGV; ulimit -c 0; |
|
|
| ulimit -v $v && "$@" |
| ) >/dev/null 2>&1 |
|
|
| ret=$? |
|
|
| local ulimit_end_=$(date +%s) || skip_ 'ulimit: date error' |
|
|
| |
| |
| test $(($ulimit_end_ - $ulimit_start_)) -ge 10 && skip_ 'ulimit too slow' |
|
|
| return $ret |
| } |
|
|
| |
| |
| |
| get_min_ulimit_v_() |
| { |
| local v |
| local page_size |
|
|
| |
| page_size=$(getconf PAGESIZE || echo 4096) |
| page_size=$(($page_size / 1024)) |
|
|
| for v in $( seq 5000 5000 50000 ); do |
| ulimit_supported_ $v "$@"; ret=$? |
| test $ret = 77 && break; |
| if test $ret = 0; then |
| local prev_v |
| prev_v=$v |
| for v in $( seq $(($prev_v-1000)) -1000 1000 ); do |
| ulimit_supported_ $v "$@"; ret=$? |
| test $ret = 77 && break 2; |
| test $ret = 0 || |
| { |
| ret_v=$((prev_v + $page_size)) |
| echo $ret_v |
| return 0 |
| } |
| prev_v=$v |
| done |
| fi |
| done |
| |
| |
| echo 1; return 1 |
| } |
|
|
| require_readable_root_() |
| { |
| test -r / || skip_ "/ is not readable" |
| } |
|
|
| |
| |
| 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' |
|
|
| |
| |
| 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 |
| } |
|
|
| |
| |
| |
| |
| require_valgrind_() |
| { |
| valgrind --error-exitcode=1 true 2>/dev/null || |
| skip_ "requires a working valgrind" |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| 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_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_() |
| { |
| |
| my_uid=$(id -u) \ |
| || { echo "$0: cannot run 'id -u'" 1>&2; return 1; } |
|
|
| |
| 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 |
| } |
|
|
| |
| |
| |
| 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 |
|
|
| |
| |
| |
| |
| |
| |
| 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" |
| } |
|
|
| |
| |
| |
| stty_reversible_init_() |
| { |
| require_perl_ |
| |
| stty_reversible_=' '$(perl -lne '/^ *{"(.*?)",.*\bREV\b/ and print $1' \ |
| "$abs_top_srcdir"/src/stty.c | tr '\n' ' ') |
| |
| |
| test 62 -le $(echo "$stty_reversible_"|wc -w) \ |
| || framework_failure_ "too few reversible settings" |
| } |
|
|
| |
| 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 ;; |
| *) ;; |
| 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 |
| } |
|
|
| |
| |
| 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)} |
|
|
| |
| |
| 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"; } |
|
|
| |
| |
| require_membership_in_two_groups_() |
| { |
| test $# = 0 || framework_failure_ |
|
|
| |
| overflow_gid=$(cat /proc/sys/kernel/overflowgid 2>/dev/null) |
| : "${overflow_gid:=1}" |
|
|
| groups= |
| for group_ in 1 \ |
| ${COREUTILS_GROUPS-$( (id -G || /usr/xpg4/bin/id -G) 2>/dev/null)} |
| do |
| |
| |
| case $group_ in |
| $overflow_gid | 1 | 32767 | 65535 | 2147483647 | 4294967295) ;; |
| 9223372036854775807 | 18446744073709551615) ;; |
| *) test -z "$groups" || groups="$groups " |
| groups="$groups$group_";; |
| esac |
| done |
| 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 |
| } |
|
|
| |
| 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 |
| } |
|
|
| |
| |
| require_trap_signame_() |
| { |
| (trap '' CHLD) || skip_ 'requires trap with signal name support' |
| } |
|
|
| |
| |
| require_kill_group_() |
| { |
| kill -0 -- -1 || skip_ 'requires kill with group signaling support' |
| } |
|
|
| |
| |
| seek_data_capable_() |
| { |
| |
| |
| if ! truncate -s16M file.sparse_; then |
| warn_ "can't create a sparse file: assuming not SEEK_DATA capable" |
| return 1 |
| fi |
| if ! cp --debug --reflink=never file.sparse_ file.sparse_.cp \ |
| | grep SEEK_HOLE; then |
| return 1 |
| fi |
|
|
| |
| { python3 < /dev/null && PYTHON_=python3; } || |
| { python < /dev/null && PYTHON_=python; } |
|
|
| if test x"$PYTHON_" = x; then |
| warn_ 'seek_data_capable_: python missing: assuming not SEEK_DATA capable' |
| return 1 |
| fi |
|
|
| |
| |
| |
| |
| timeout 1 true >/dev/null && TIMEOUT_='timeout 10' |
|
|
| $TIMEOUT_ $PYTHON_ "$abs_srcdir"/tests/seek-data-capable "$@" |
| } |
|
|
| |
| 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 |
| } |
|
|
| |
| require_perl_() |
| { |
| : ${PERL=perl} |
| $PERL -e 'use warnings' > /dev/null 2>&1 \ |
| || skip_ 'configure did not find a usable version of Perl' |
| } |
|
|
| |
| require_sparse_support_() |
| { |
| test $# = 0 || framework_failure_ |
| |
| |
| |
| 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 |
| } |
|
|
| |
| gcc_shared_libs_= |
|
|
| |
| |
| |
| gcc_shared_() |
| { |
| local in=$1 |
| local out=$2 |
| shift 2 || return 1 |
|
|
| $CC -Wall -shared --std=gnu99 -fPIC -O2 $* "$in" -o "$out" $gcc_shared_libs_ |
| } |
|
|
| |
| |
| |
| require_gcc_shared_() |
| { |
| |
| gcc_shared_libs_='-ldl' |
| if gcc_shared_ '-' 'd.so' -xc < /dev/null 2>&1; then |
| : |
| else |
| gcc_shared_libs_= |
| if gcc_shared_ '-' 'd.so' -xc < /dev/null 2>&1; then |
| : |
| else |
| skip_ '$CC -shared ... failed to build a shared lib' |
| fi |
| fi |
| rm -f d.so |
| } |
|
|
| mkfifo_or_skip_() |
| { |
| test $# = 1 || framework_failure_ |
| if ! mkfifo "$1"; then |
| |
| |
| |
| |
| |
| skip_ 'unable to create a fifo' |
| fi |
| } |
|
|
| trap_sigpipe_or_skip_() |
| { |
| timeout 1 true >/dev/null || |
| skip_ 'trapping SIGPIPE cannot be safely checked' |
|
|
| (trap '' PIPE && timeout 10 yes |:) 2>&1 | grep 'Broken pipe' >/dev/null || |
| skip_ 'trapping SIGPIPE is not supported' |
| } |
|
|
| require_bash_as_SHELL_() |
| { |
| if bash --version >/dev/null 2>&1; then |
| SHELL='bash' |
| else |
| skip_ 'bash is required' |
| fi |
| } |
|
|
| |
| |
| 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);; |
| *) skip_ 'this directory has the setgid bit set';; |
| esac |
| } |
|
|
| |
| |
| |
| |
| 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_ |
|
|
| |
| |
| |
| __ctx=$(stat --printf='%C\n' .) || framework_failure_ |
| case $__ctx in |
| *:*:*:*) __ctx_ok=1 ;; |
| *:*:*) |
| mls_enabled_ || __ctx_ok=1 ;; |
| esac |
|
|
| test "$__ctx_ok" || |
| skip_ "unexpected context '$__ctx'; turn off mcstransd" |
| } |
|
|
| |
| |
| |
| 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_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 |
| } |
|
|
| |
| |
| print_ver_() |
| { |
| require_built_ "$@" |
| if test "$VERBOSE" = yes; then |
| local i |
| for i in $*; do |
| env $i --version |
| done |
| fi |
| } |
|
|
| |
| require_gnu_() |
| { |
| test "$(uname)" = GNU \ |
| || skip_ 'not running on GNU/Hurd' |
| } |
|
|
| sanitize_path_ |
|
|