1# This file is sourced by init.sh, *before* its initialization. 2 3# Copyright (C) 2010-2018 Free Software Foundation, Inc. 4 5# This program is free software: you can redistribute it and/or modify 6# it under the terms of the GNU General Public License as published by 7# the Free Software Foundation, either version 3 of the License, or 8# (at your option) any later version. 9 10# This program is distributed in the hope that it will be useful, 11# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13# GNU General Public License for more details. 14 15# You should have received a copy of the GNU General Public License 16# along with this program. If not, see <https://www.gnu.org/licenses/>. 17 18# This goes hand in hand with the "exec 9>&2;" in tests/Makefile.am's 19# TESTS_ENVIRONMENT definition. 20stderr_fileno_=9 21 22# Having an unsearchable directory in PATH causes execve to fail with EACCES 23# when applied to an unresolvable program name, contrary to the desired ENOENT. 24# Avoid the problem by rewriting PATH to exclude unsearchable directories. 25# Also, if PATH lacks /sbin and/or /usr/sbin, append it/them. 26sanitize_path_() 27{ 28 # FIXME: remove double quotes around $IFS when all tests use init.sh. 29 # They constitute a work-around for a bug in FreeBSD 8.1's /bin/sh. 30 local saved_IFS="$IFS" 31 IFS=: 32 set -- $PATH 33 IFS=$saved_IFS 34 35 local d d1 36 local colon= 37 local new_path= 38 for d in "$@"; do 39 test -z "$d" && d1=. || d1=$d 40 if ls -d "$d1/." > /dev/null 2>&1; then 41 new_path="$new_path$colon$d" 42 colon=':' 43 fi 44 done 45 46 for d in /sbin /usr/sbin ; do 47 case ":$new_path:" in 48 *:$d:*) ;; 49 *) new_path="$new_path:$d" ;; 50 esac 51 done 52 53 PATH=$new_path 54 export PATH 55} 56 57getlimits_() 58{ 59 eval $(getlimits) 60 test "$INT_MAX" || fatal_ "running getlimits" 61} 62 63require_no_default_acl_() 64{ 65 if getfacl --version < /dev/null > /dev/null 2>&1; then 66 getfacl "$1" | grep '^default:' && skip_ 'Default ACL detected' 67 else 68 ls -ld "$1" | grep '.........+' && skip_ 'ACL detected' 69 fi 70} 71 72require_acl_() 73{ 74 getfacl --version < /dev/null > /dev/null 2>&1 \ 75 && setfacl --version < /dev/null > /dev/null 2>&1 \ 76 || skip_ "This test requires getfacl and setfacl." 77 78 id -u bin > /dev/null 2>&1 \ 79 || skip_ "This test requires a local user named bin." 80} 81 82is_local_dir_() 83{ 84 test $# = 1 || framework_failure_ 85 df --local "$1" >/dev/null 2>&1 86} 87 88require_mount_list_() 89{ 90 local mount_list_fail='cannot read table of mounted file systems' 91 df --local 2>&1 | grep -F "$mount_list_fail" >/dev/null && 92 skip_ "$mount_list_fail" 93} 94 95dump_mount_list_() 96{ 97 cat /proc/self/mountinfo || 98 cat /proc/self/mounts || 99 cat /proc/mounts || 100 cat /etc/mtab 101} 102 103require_local_dir_() 104{ 105 require_mount_list_ 106 is_local_dir_ . || 107 skip_ "This test must be run on a local file system." 108} 109 110require_selinux_() 111{ 112 # When in a chroot of an SELinux-enabled system, but with a mock-simulated 113 # SELinux-*disabled* system, recognize that SELinux is disabled system wide: 114 grep 'selinuxfs$' /proc/filesystems > /dev/null \ 115 || skip_ "this system lacks SELinux support" 116 117 # Independent of whether SELinux is enabled system-wide, 118 # the current file system may lack SELinux support. 119 # Also the current build may have SELinux support disabled. 120 case $(ls -Zd .) in 121 '? .'|'unlabeled .') 122 test -z "$CONFIG_HEADER" \ 123 && framework_failure_ 'CONFIG_HEADER not defined' 124 grep '^#define HAVE_SELINUX_SELINUX_H 1' "$CONFIG_HEADER" > /dev/null \ 125 && selinux_missing_="(file) system" || selinux_missing_="build" 126 skip_ "this $selinux_missing_ lacks SELinux support" 127 ;; 128 esac 129} 130 131# Return the SELinux type component if available 132get_selinux_type() { ls -Zd "$1" | sed -n 's/.*:\(.*_t\)[: ].*/\1/p'; } 133 134# Whether SELinux Multi Level Security is enabled 135mls_enabled_() { 136 sestatus 2>&1 | 137 grep 'Policy MLS status:.*enabled' > /dev/null 138} 139 140# Skip this test if we're not in SELinux "enforcing" mode. 141require_selinux_enforcing_() 142{ 143 require_selinux_ 144 test "$(getenforce)" = Enforcing \ 145 || skip_ "This test is useful only with SELinux in Enforcing mode." 146} 147 148require_smack_() 149{ 150 grep 'smackfs$' /proc/filesystems > /dev/null \ 151 || skip_ "this system lacks SMACK support" 152 153 test "$(ls -Zd .)" != '? .' \ 154 || skip_ "this file system lacks SMACK support" 155} 156 157require_openat_support_() 158{ 159 # Skip this test if your system has neither the openat-style functions 160 # nor /proc/self/fd support with which to emulate them. 161 162 test -z "$CONFIG_HEADER" \ 163 && framework_failure_ 'CONFIG_HEADER not defined' 164 165 _skip=yes 166 grep '^#define HAVE_OPENAT' "$CONFIG_HEADER" > /dev/null && _skip=no 167 test -d /proc/self/fd && _skip=no 168 if test $_skip = yes; then 169 skip_ 'this system lacks openat support' 170 fi 171} 172 173# Return true if command runs with the 174# ulimit specified in the first argument 175ulimit_supported_() 176{ 177 local v 178 v="$1" 179 shift 180 181 ( 182 # Try to disable core dumps which may 183 # occur with memory constraints 184 trap '' SEGV; ulimit -c 0; 185 186 ulimit -v $v && "$@" 187 ) >/dev/null 2>&1 188} 189 190# Determine the minimum required VM limit to run the given command. 191# Output that value to stdout ... to be used by the caller. 192# Return 0 in case of success, and a non-Zero value otherwise. 193get_min_ulimit_v_() 194{ 195 local v 196 local page_size 197 198 # Increase result by this amount to avoid alignment issues 199 page_size=$(getconf PAGESIZE || echo 4096) 200 page_size=$(($page_size / 1024)) 201 202 for v in $( seq 5000 5000 50000 ); do 203 if ulimit_supported_ $v "$@"; then 204 local prev_v 205 prev_v=$v 206 for v in $( seq $(($prev_v-1000)) -1000 1000 ); do 207 ulimit_supported_ $v "$@" || 208 { 209 ret_v=$((prev_v + $page_size)) 210 echo $ret_v 211 return 0 212 } 213 prev_v=$v 214 done 215 fi 216 done 217 # The above did not find a working limit. Echo a very small number - just 218 # in case the caller does not handle the non-Zero return value. 219 echo 1; return 1 220} 221 222require_readable_root_() 223{ 224 test -r / || skip_ "/ is not readable" 225} 226 227# Skip the current test if strace is not available or doesn't work 228# with the named syscall. Usage: require_strace_ unlink 229require_strace_() 230{ 231 test $# = 1 || framework_failure_ 232 233 strace -V < /dev/null > /dev/null 2>&1 || 234 skip_ 'no strace program' 235 236 strace -qe "$1" echo > /dev/null 2>&1 || 237 skip_ 'strace -qe "'"$1"'" does not work' 238 239 # On some linux/sparc64 systems, strace works fine on 32-bit executables, 240 # but prints only one line of output for every 64-bit executable. 241 strace -o log-help ls --help >/dev/null || framework_failure_ 242 n_lines_help=$(wc -l < log-help) 243 rm -f log-help 244 if test $n_lines_help = 0 || test $n_lines_help = 1; then 245 skip_ 'strace produces no more than one line of output' 246 fi 247} 248 249# Skip the current test if valgrind doesn't work, 250# which could happen if not installed, 251# or hasn't support for the built architecture, 252# or hasn't appropriate error suppressions installed etc. 253require_valgrind_() 254{ 255 valgrind --error-exitcode=1 true 2>/dev/null || 256 skip_ "requires a working valgrind" 257} 258 259# Skip the current test if setfacl doesn't work on the current file system, 260# which could happen if not installed, or if ACLs are not supported by the 261# kernel or the file system, or are turned off via mount options. 262# 263# Work around the following two issues: 264# 265# 1) setfacl maps ACLs into file permission bits if on "noacl" file systems. 266# 267# On file systems which do not support ACLs (e.g. ext4 mounted with -o noacl), 268# setfacl operates on the regular file permission bits, and only fails if the 269# given ACL spec does not fit into there. Thus, to test if ACLs really work 270# on the current file system, pass an ACL spec which can't be mapped that way. 271# "Default" ACLs (-d) seem to fulfill this requirement. 272# 273# 2) setfacl only invokes the underlying system call if the ACL would change. 274# 275# If the given ACL spec would not change the ACLs on the file, then setfacl 276# does not invoke the underlying system call - setxattr(). Therefore, to test 277# if setting ACLs really works on the current file system, call setfacl twice 278# with conflictive ACL specs. 279require_setfacl_() 280{ 281 local d='acltestdir_' 282 mkdir $d || framework_failure_ 283 local f=0 284 285 setfacl -d -m user::r-x $d \ 286 && setfacl -d -m user::rwx $d \ 287 || f=1 288 rm -rf $d || framework_failure_ 289 test $f = 0 \ 290 || skip_ "setfacl does not work on the current file system" 291} 292 293# Require a controlling input 'terminal'. 294require_controlling_input_terminal_() 295{ 296 have_input_tty=yes 297 tty -s || have_input_tty=no 298 test -t 0 || have_input_tty=no 299 if test "$have_input_tty" = no; then 300 skip_ 'requires controlling input terminal 301This test must have a controlling input "terminal", so it may not be 302run via "batch", "at", or "ssh". On some systems, it may not even be 303run in the background.' 304 fi 305} 306 307require_built_() 308{ 309 skip_=no 310 for i in "$@"; do 311 case " $built_programs " in 312 *" $i "*) ;; 313 *) echo "$i: not built" 1>&2; skip_=yes ;; 314 esac 315 done 316 317 test $skip_ = yes && skip_ "required program(s) not built" 318} 319 320require_file_system_bytes_free_() 321{ 322 local req=$1 323 local expr=$(stat -f --printf "$req / %S <= %a" .) 324 $AWK "BEGIN{ exit !($expr) }" \ 325 || skip_ "this test needs at least $req bytes of free space" 326} 327 328uid_is_privileged_() 329{ 330 # Make sure id -u succeeds. 331 my_uid=$(id -u) \ 332 || { echo "$0: cannot run 'id -u'" 1>&2; return 1; } 333 334 # Make sure it gives valid output. 335 case $my_uid in 336 0) ;; 337 *[!0-9]*) 338 echo "$0: invalid output ('$my_uid') from 'id -u'" 1>&2 339 return 1 ;; 340 *) return 1 ;; 341 esac 342} 343 344get_process_status_() 345{ 346 sed -n '/^State:[ ]*\([[:alpha:]]\).*/s//\1/p' /proc/$1/status 347} 348 349# Convert an ls-style permission string, like drwxr----x and -rw-r-x-wx 350# to the equivalent chmod --mode (-m) argument, (=,u=rwx,g=r,o=x and 351# =,u=rw,g=rx,o=wx). Ignore ACLs. 352rwx_to_mode_() 353{ 354 case $# in 355 1) rwx=$1;; 356 *) echo "$0: wrong number of arguments" 1>&2 357 echo "Usage: $0 ls-style-mode-string" 1>&2 358 return;; 359 esac 360 361 case $rwx in 362 [ld-][rwx-][rwx-][rwxsS-][rwx-][rwx-][rwxsS-][rwx-][rwx-][rwxtT-]) ;; 363 [ld-][rwx-][rwx-][rwxsS-][rwx-][rwx-][rwxsS-][rwx-][rwx-][rwxtT-][+.]) ;; 364 *) echo "$0: invalid mode string: $rwx" 1>&2; return;; 365 esac 366 367 # Perform these conversions: 368 # S s 369 # s xs 370 # T t 371 # t xt 372 # The 'T' and 't' ones are only valid for 'other'. 373 s='s/S/@/;s/s/x@/;s/@/s/' 374 t='s/T/@/;s/t/x@/;s/@/t/' 375 376 u=$(echo $rwx|sed 's/^.\(...\).*/,u=\1/;s/-//g;s/^,u=$//;'$s) 377 g=$(echo $rwx|sed 's/^....\(...\).*/,g=\1/;s/-//g;s/^,g=$//;'$s) 378 o=$(echo $rwx|sed 's/^.......\(...\).*/,o=\1/;s/-//g;s/^,o=$//;'$s';'$t) 379 echo "=$u$g$o" 380} 381 382# Set the global variable stty_reversible_ to a space-separated list of the 383# reversible settings from stty.c. stty_reversible_ also starts and ends 384# with a space. 385stty_reversible_init_() 386{ 387 # Pad start with one space for the first option to match in query function. 388 stty_reversible_=' '$(perl -lne '/^ *{"(.*?)",.*\bREV\b/ and print $1' \ 389 "$abs_top_srcdir"/src/stty.c | tr '\n' ' ') 390 # Ensure that there are at least 62, i.e., so we're alerted if 391 # reformatting the source empties the list. 392 test 62 -le $(echo "$stty_reversible_"|wc -w) \ 393 || framework_failure_ "too few reversible settings" 394} 395 396# Test whether $1 is one of stty's reversible options. 397stty_reversible_query_() 398{ 399 case $stty_reversible_ in 400 '') 401 framework_failure_ "stty_reversible_init_() not called?";; 402 *" $1 "*) 403 return 0;; 404 *) 405 return 1;; 406 esac 407} 408 409skip_if_() 410{ 411 case $1 in 412 root) skip_ must be run as root ;; 413 non-root) skip_ must be run as non-root ;; 414 *) ;; # FIXME? 415 esac 416} 417 418very_expensive_() 419{ 420 if test "$RUN_VERY_EXPENSIVE_TESTS" != yes; then 421 skip_ 'very expensive: disabled by default 422This test is very expensive, so it is disabled by default. 423To run it anyway, rerun make check with the RUN_VERY_EXPENSIVE_TESTS 424environment variable set to yes. E.g., 425 426 env RUN_VERY_EXPENSIVE_TESTS=yes make check 427 428or use the shortcut target of the toplevel Makefile, 429 430 make check-very-expensive 431' 432 fi 433} 434 435expensive_() 436{ 437 if test "$RUN_EXPENSIVE_TESTS" != yes; then 438 skip_ 'expensive: disabled by default 439This test is relatively expensive, so it is disabled by default. 440To run it anyway, rerun make check with the RUN_EXPENSIVE_TESTS 441environment variable set to yes. E.g., 442 443 env RUN_EXPENSIVE_TESTS=yes make check 444 445or use the shortcut target of the toplevel Makefile, 446 447 make check-expensive 448' 449 fi 450} 451 452# Test whether we can run our just-built root owned rm, 453# i.e., that $NON_ROOT_USERNAME has access to the build directory. 454nonroot_has_perm_() 455{ 456 require_built_ chroot 457 458 local rm_version=$( 459 chroot --skip-chdir --user=$NON_ROOT_USERNAME / env PATH="$PATH" \ 460 rm --version | 461 sed -n '1s/.* //p' 462 ) 463 case ":$rm_version:" in 464 :$PACKAGE_VERSION:) ;; 465 *) return 1;; 466 esac 467} 468 469require_root_() 470{ 471 uid_is_privileged_ || skip_ "must be run as root" 472 NON_ROOT_USERNAME=${NON_ROOT_USERNAME=nobody} 473 NON_ROOT_GID=${NON_ROOT_GID=$(id -g $NON_ROOT_USERNAME)} 474 475 # When the current test invokes chroot, call nonroot_has_perm_ 476 # to check for a common problem. 477 grep '^[ ]*chroot' "../$0" \ 478 && { nonroot_has_perm_ \ 479 || skip_ "user $NON_ROOT_USERNAME lacks execute permissions"; } 480} 481 482skip_if_root_() { uid_is_privileged_ && skip_ "must be run as non-root"; } 483 484# Set 'groups' to a space-separated list of at least two groups 485# of which the user is a member. 486require_membership_in_two_groups_() 487{ 488 test $# = 0 || framework_failure_ 489 490 groups=${COREUTILS_GROUPS-$( (id -G || /usr/xpg4/bin/id -G) 2>/dev/null)} 491 case "$groups" in 492 *' '*) ;; 493 *) skip_ 'requires membership in two groups 494this test requires that you be a member of more than one group, 495but running 'id -G'\'' either failed or found just one. If you really 496are a member of at least two groups, then rerun this test with 497COREUTILS_GROUPS set in your environment to the space-separated list 498of group names or numbers. E.g., 499 500 env COREUTILS_GROUPS='\''users cdrom'\'' make check 501 502' 503 ;; 504 esac 505} 506 507# Is /proc/$PID/status supported? 508require_proc_pid_status_() 509{ 510 sleep 2 & 511 local pid=$! 512 sleep .5 513 grep '^State:[ ]*[S]' /proc/$pid/status > /dev/null 2>&1 || 514 skip_ "/proc/$pid/status: missing or 'different'" 515 kill $pid 516} 517 518# Does trap support signal names? 519# Old versions of ash did not. 520require_trap_signame_() 521{ 522 (trap '' CHLD) || skip_ 'requires trap with signal name support' 523} 524 525# Does kill support sending signal to whole group? 526# dash 0.5.8 at least does not. 527require_kill_group_() 528{ 529 kill -0 -- -1 || skip_ 'requires kill with group signalling support' 530} 531 532# Return nonzero if the specified path is on a file system for 533# which FIEMAP support exists. Note some file systems (like ext3 and btrfs) 534# only support FIEMAP for files, not directories. 535fiemap_capable_() 536{ 537 if ! python < /dev/null; then 538 warn_ 'fiemap_capable_: python missing: assuming not fiemap capable' 539 return 1 540 fi 541 python "$abs_srcdir"/tests/fiemap-capable "$@" 542} 543 544# Skip the current test if "." lacks d_type support. 545require_dirent_d_type_() 546{ 547 python < /dev/null \ 548 || skip_ python missing: assuming no d_type support 549 550 python "$abs_srcdir"/tests/d_type-check \ 551 || skip_ requires d_type support 552} 553 554# Skip the current test if we lack Perl. 555require_perl_() 556{ 557 : ${PERL=perl} 558 $PERL -e 'use warnings' > /dev/null 2>&1 \ 559 || skip_ 'configure did not find a usable version of Perl' 560} 561 562# Does the current (working-dir) file system support sparse files? 563require_sparse_support_() 564{ 565 test $# = 0 || framework_failure_ 566 # Test whether we can create a sparse file. 567 # For example, on Darwin6.5 with a file system of type hfs, it's not possible. 568 # NTFS requires 128K before a hole appears in a sparse file. 569 t=sparse.$$ 570 dd bs=1 seek=128K of=$t < /dev/null 2> /dev/null 571 set x $(du -sk $t) 572 kb_size=$2 573 rm -f $t 574 if test $kb_size -ge 128; then 575 skip_ 'this file system does not support sparse files' 576 fi 577} 578 579# Compile a shared lib using the GCC options for doing so. 580# Pass input and output file as parameters respectively. 581# Any other optional parmeters are passed to $CC. 582gcc_shared_() 583{ 584 local in=$1 585 local out=$2 586 shift 2 || return 1 587 588 $CC -Wall -shared --std=gnu99 -fPIC -O2 $* "$in" -o "$out" -ldl 589} 590 591# There are a myriad of ways to build shared libs, 592# so we only consider running tests requiring shared libs, 593# on platforms that support building them as follows. 594require_gcc_shared_() 595{ 596 gcc_shared_ '-' 'd.so' -xc < /dev/null 2>&1 \ 597 || skip_ '$CC -shared ... failed to build a shared lib' 598 rm -f d.so 599} 600 601mkfifo_or_skip_() 602{ 603 test $# = 1 || framework_failure_ 604 if ! mkfifo "$1"; then 605 # Make an exception of this case -- usually we interpret framework-creation 606 # failure as a test failure. However, in this case, when running on a SunOS 607 # system using a disk NFS mounted from OpenBSD, the above fails like this: 608 # mkfifo: cannot make fifo 'fifo-10558': Not owner 609 skip_ 'unable to create a fifo' 610 fi 611} 612 613# Disable the current test if the working directory seems to have 614# the setgid bit set. 615skip_if_setgid_() 616{ 617 setgid_tmpdir=setgid-$$ 618 (umask 77; mkdir $setgid_tmpdir) 619 perms=$(stat --printf %A $setgid_tmpdir) 620 rmdir $setgid_tmpdir 621 case $perms in 622 drwx------);; 623 drwxr-xr-x);; # Windows98 + DJGPP 2.03 624 *) skip_ 'this directory has the setgid bit set';; 625 esac 626} 627 628# Skip if files are created with a different group to the current user 629# This can happen due to a setgid dir, or by some other mechanism on OS X: 630# https://unix.stackexchange.com/q/63865 631# https://bugs.gnu.org/14024#41 632skip_if_nondefault_group_() 633{ 634 touch grp.$$ 635 gen_ug=$(stat -c '%u:%g' grp.$$) 636 rm grp.$$ 637 test "$gen_ug" = "$(id -ru):$(id -rg)" || 638 skip_ 'Files are created with a different gid' 639} 640 641skip_if_mcstransd_is_running_() 642{ 643 test $# = 0 || framework_failure_ 644 645 # When mcstransd is running, you'll see only the 3-component 646 # version of file-system context strings. Detect that, 647 # and if it's running, skip this test. 648 __ctx=$(stat --printf='%C\n' .) || framework_failure_ 649 case $__ctx in 650 *:*:*:*) __ctx_ok=1 ;; # four components is ok 651 *:*:*) # three components is ok too if there is no MLS 652 mls_enabled_ || __ctx_ok=1 ;; 653 esac 654 655 test "$__ctx_ok" || 656 skip_ "unexpected context '$__ctx'; turn off mcstransd" 657} 658 659# Skip the current test if umask doesn't work as usual. 660# This test should be run in the temporary directory that ends 661# up being removed via the trap commands. 662working_umask_or_skip_() 663{ 664 umask 022 665 touch file1 file2 666 chmod 644 file2 667 perms=$(ls -l file1 file2 | sed 's/ .*//' | uniq) 668 rm -f file1 file2 669 670 case $perms in 671 *' 672 '*) skip_ 'your build directory has unusual umask semantics' 673 esac 674} 675 676# Retry a function requiring a sufficient delay to _pass_ 677# using a truncated exponential backoff method. 678# Example: retry_delay_ dd_reblock_1 .1 6 679# This example will call the dd_reblock_1 function with 680# an initial delay of .1 second and call it at most 6 times 681# with a max delay of 3.2s (doubled each time), or a total of 6.3s 682# Note ensure you do _not_ quote the parameter to GNU sleep in 683# your function, as it may contain separate values that sleep 684# needs to accumulate. 685# Further function arguments will be forwarded to the test function. 686retry_delay_() 687{ 688 local test_func=$1 689 local init_delay=$2 690 local max_n_tries=$3 691 shift 3 || return 1 692 693 local attempt=1 694 local num_sleeps=$attempt 695 local time_fail 696 while test $attempt -le $max_n_tries; do 697 local delay=$($AWK -v n=$num_sleeps -v s="$init_delay" \ 698 'BEGIN { print s * n }') 699 "$test_func" "$delay" "$@" && { time_fail=0; break; } || time_fail=1 700 attempt=$(expr $attempt + 1) 701 num_sleeps=$(expr $num_sleeps '*' 2) 702 done 703 test "$time_fail" = 0 704} 705 706# Call this with a list of programs under test immediately after 707# sourcing init.sh. 708print_ver_() 709{ 710 require_built_ "$@" 711 if test "$VERBOSE" = yes; then 712 local i 713 for i in $*; do 714 env $i --version 715 done 716 fi 717} 718 719# Are we running on GNU/Hurd? 720require_gnu_() 721{ 722 test "$(uname)" = GNU \ 723 || skip_ 'not running on GNU/Hurd' 724} 725 726sanitize_path_ 727