1#!/bin/sh 2# 3# Automated tests for utimensat() 4# 5# Copyright (C) 2008, Linux Foundation 6# Written by Michael Kerrisk <mtk.manpages@gmail.com> 7# Licensed under GPLv2 or later 8# 9# Not (yet) included in this automated test set: 10# * AT_SYMLINK_NOFOLLOW in flags: If pathname specifies a symbolic link, 11# then update the timestamps of the link, rather than the file to which 12# it refers. 13# * Setting of nanosecond components of timestamps (support for 14# nanosecond timestamps is file-system-dependent) 15# * "Updated file timestamps are set to the greatest value supported 16# by the file system that is not greater than the specified time." 17# (i.e., if we set timestamp to {0, 999999999}, then the setting 18# is rounded down, rather than up, to unit of timestamp resolution. 19# * Privileged processes should be able to bypass permission checks. 20# (except when file is marked with the "Immutable" EFA). 21 22#===================================================================== 23 24export TCID=utimensat01 25export TST_TOTAL=99 26export TST_COUNT=0 27. test.sh 28 29if tst_kvcmp -lt "2.6.22"; then 30 tst_brkm TCONF "System kernel version is less than 2.6.22,cannot execute test" 31fi 32 33# Starting with 4.8.0 operations on immutable files return EPERM instead of 34# EACCES. 35if tst_kvcmp -lt "4.8.0"; then 36 imaccess=EACCES 37else 38 imaccess=EPERM 39fi 40 41 42RESULT_FILE=$TMPDIR/utimensat.result 43 44TEST_DIR=$TMPDIR/utimensat_tests 45FILE=$TEST_DIR/utimensat.test_file 46 47TEST_PROG=utimensat01 48 49if [ ! -f $LTPROOT/testcases/bin/$TEST_PROG ]; then 50 tst_brkm TWARN "$LTPROOT/testcases/bin/$TEST_PROG is missing (please check install)" 51fi 52 53# Summary counters of all test results 54 55test_num=0 56failed_cnt=0 57passed_cnt=0 58failed_list="" 59 60#===================================================================== 61 62setup_file() 63{ 64# $1 is test file pathname 65# $2 is owner for test file (chown(1)) 66# $3 is permissions for test file (chmod(1)) 67# $4 is "ext2" extended file attributes for test file (chattr(1)) 68 69 FILE=$1 70 71 # Make sure any old version of file is deleted 72 73 if test -e $FILE; then 74 sudo $s_arg chattr -ai $FILE || return $? 75 sudo $s_arg rm -f $FILE || return $? 76 fi 77 78 # Create file and make atime and mtime zero. 79 80 sudo $s_arg -u $test_user touch $FILE || return $? 81 if ! $TEST_PROG -q $FILE 0 0 0 0 > $RESULT_FILE; then 82 echo "Failed to set up test file $FILE" 1>&2 83 exit 1 84 fi 85 86 read res atime mtime < $RESULT_FILE 87 if test "X$res" != "XSUCCESS" || 88 test $atime -ne 0 || test $mtime != 0; then 89 echo "Failed to set correct times on test file $FILE" 1>&2 90 exit 1 91 fi 92 93 # Set owner, permissions, and EFAs for file. 94 95 if test -n "$2"; then 96 sudo $s_arg chown $2 $FILE || return $? 97 fi 98 99 sudo $s_arg chmod $3 $FILE || return $? 100 101 if test -n "$4"; then 102 sudo $s_arg chattr $4 $FILE || return $? 103 fi 104 105 # Display file setup, for visual verification 106 107 ls -l $FILE | awk '{ printf "Owner=%s; perms=%s; ", $3, $1}' 108 if ! sudo $s_arg lsattr -l $FILE | sed 's/, /,/g' | awk '{print "EFAs=" $2}' 109 then 110 return $? 111 fi 112 113} 114 115test_failed() 116{ 117 tst_resm TFAIL "FAILED test $test_num" 118 119 failed_cnt=$(expr $failed_cnt + 1) 120 failed_list="$failed_list $test_num" 121} 122 123check_result() 124{ 125 STATUS=$1 # Exit status from test program 126 EXPECTED_RESULT=$2 # SUCCESS / EACCES / EPERM / EINVAL 127 EXPECT_ATIME_CHANGED=$3 # Should be 'y' or 'n' (only for SUCCESS) 128 EXPECT_MTIME_CHANGED=$4 # Should be 'y' or 'n' (only for SUCCESS) 129 130 test_num=$(expr $test_num + 1) 131 132 # If our test setup failed, stop immediately 133 134 if test $STATUS -gt 1; then 135 echo "FAILED (bad test setup)" 136 exit 1 137 fi 138 139 read res atime mtime < $RESULT_FILE 140 141 echo "EXPECTED: $EXPECTED_RESULT $EXPECT_ATIME_CHANGED "\ 142 "$EXPECT_MTIME_CHANGED" 143 echo "RESULT: $res $atime $mtime" 144 145 if test "$res" != "$EXPECTED_RESULT"; then 146 test_failed 147 return 148 fi 149 150 passed=1 151 152 # If the test program exited successfully, then check that atime and 153 # and mtime were updated / not updated, as expected. 154 155 if test $EXPECTED_RESULT = "SUCCESS"; then 156 if test $EXPECT_ATIME_CHANGED = "y"; then 157 if test $atime -eq 0; then 158 echo "atime should have changed, but did not" 159 passed=0 160 fi 161 else 162 if test $atime -ne 0; then 163 echo "atime should not have changed, but did" 164 passed=0 165 fi 166 fi 167 168 if test $EXPECT_MTIME_CHANGED = "y"; then 169 if test $mtime -eq 0; then 170 echo "mtime should have changed, but did not" 171 passed=0 172 fi 173 else 174 if test $mtime -ne 0; then 175 echo "mtime should not have changed, but did" 176 passed=0 177 fi 178 fi 179 180 if test $passed -eq 0; then 181 test_failed 182 return 183 fi 184 fi 185 186 passed_cnt=$(expr $passed_cnt + 1) 187 tst_resm TPASS "PASSED test $test_num" 188} 189 190run_test() 191{ 192 # By default, we do three types of test: 193 # a) pathname (pathname != NULL) 194 # b) readable file descriptor (pathname == NULL, dirfd opened O_RDONLY) 195 # c) writable file descriptor (pathname == NULL, dirfd opened O_RDWR). 196 # For this case we also include O_APPEND in open flags, since that 197 # is needed if testing with a file that has the Append-only 198 # attribute enabled. 199 200 # -R says don't do tests with readable file descriptor 201 # -W says don't do tests with writable file descriptor 202 203 OPTIND=1 204 205 do_read_fd_test=1 206 do_write_fd_test=1 207 while getopts "RW" opt; do 208 case "$opt" in 209 R) do_read_fd_test=0 210 ;; 211 W) do_write_fd_test=0 212 ;; 213 *) echo "run_test: bad usage" 214 exit 1 215 ;; 216 esac 217 done 218 shift `expr $OPTIND - 1` 219 220 echo "Pathname test" 221 setup_file $FILE "$1" "$2" "$3" 222 cp $LTPROOT/testcases/bin/$TEST_PROG ./ 223 CMD="./$TEST_PROG -q $FILE $4" 224 echo "$CMD" 225 sudo $s_arg -u $test_user $CMD > $RESULT_FILE 226 check_result $? $5 $6 $7 227 echo 228 229 if test $do_read_fd_test -ne 0; then 230 echo "Readable file descriptor (futimens(3)) test" 231 setup_file $FILE "$1" "$2" "$3" 232 CMD="./$TEST_PROG -q -d $FILE NULL $4" 233 echo "$CMD" 234 sudo $s_arg -u $test_user $CMD > $RESULT_FILE 235 check_result $? $5 $6 $7 236 echo 237 fi 238 239 # Can't do the writable file descriptor test for immutable files 240 # (even root can't open an immutable file for writing) 241 242 if test $do_write_fd_test -ne 0; then 243 echo "Writable file descriptor (futimens(3)) test" 244 setup_file $FILE "$1" "$2" "$3" 245 CMD="./$TEST_PROG -q -w -d $FILE NULL $4" 246 echo "$CMD" 247 sudo $s_arg -u $test_user $CMD > $RESULT_FILE 248 check_result $? $5 $6 $7 249 echo 250 fi 251 252 sudo $s_arg chattr -ai $FILE 253 sudo $s_arg rm -f $FILE 254} 255 256#===================================================================== 257 258# Since some automated testing systems have no tty while testing, 259# comment this line in /etc/sudoers to avoid the error message: 260# `sudo: sorry, you must have a tty to run sudo' 261# Use trap to restore this line after program terminates. 262sudoers=/etc/sudoers 263if [ ! -r $sudoers ]; then 264 tst_brkm TBROK "can't read $sudoers" 265fi 266pattern="[[:space:]]*Defaults[[:space:]]*requiretty.*" 267if grep -q "^${pattern}" $sudoers; then 268 tst_resm TINFO "Comment requiretty in $sudoers for automated testing systems" 269 if ! sed -r -i.$$ -e "s/^($pattern)/#\1/" $sudoers; then 270 tst_brkm TBROK "failed to mangle $sudoers properly" 271 fi 272 trap 'trap "" EXIT; restore_sudoers' EXIT 273fi 274 275restore_sudoers() 276{ 277 tst_resm TINFO "Restore requiretty in $sudoers" 278 mv /etc/sudoers.$$ /etc/sudoers 279} 280 281test_user=nobody 282echo "test sudo for -n option, non-interactive" 283if sudo -h | grep -q -- -n; then 284 s_arg="-n" 285 echo "sudo supports -n" 286else 287 s_arg= 288 echo "sudo does not support -n" 289fi 290 291if ! sudo $s_arg true; then 292 tst_brkm TBROK "sudo cannot be run by user non-interactively" 293fi 294if test ! -f $sudoers 295then 296 echo "root ALL=(ALL) ALL" > $sudoers || exit 297 chmod 440 $sudoers 298 trap 'trap "" EXIT; nuke_sudoers' EXIT 299fi 300 301nuke_sudoers() 302{ 303 sudo rm -f $sudoers 304} 305 306sudo $s_arg -u $test_user mkdir -p $TEST_DIR 307 308# Make sure chattr command is supported 309touch $TEST_DIR/tmp_file 310chattr +a $TEST_DIR/tmp_file 311if [ $? -ne 0 ] ; then 312 rm -rf $TEST_DIR 313 tst_brkm TCONF "chattr not supported" 314fi 315chattr -a $TEST_DIR/tmp_file 316 317cd $TEST_DIR 318chown root $LTPROOT/testcases/bin/$TEST_PROG 319chmod ugo+x,u+s $LTPROOT/testcases/bin/$TEST_PROG 320 321#===================================================================== 322 323 324echo "============================================================" 325 326echo 327echo "Testing read-only file, owned by self" 328echo 329 330echo "***** Testing times==NULL case *****" 331run_test -W "" 400 "" "" SUCCESS y y 332 333echo "***** Testing times=={ UTIME_NOW, UTIME_NOW } case *****" 334run_test -W "" 400 "" "0 n 0 n" SUCCESS y y 335 336echo "***** Testing times=={ UTIME_OMIT, UTIME_OMIT } case *****" 337run_test -W "" 400 "" "0 o 0 o" SUCCESS n n 338 339echo "***** Testing times=={ UTIME_NOW, UTIME_OMIT } case *****" 340run_test -W "" 400 "" "0 n 0 o" SUCCESS y n 341 342echo "***** Testing times=={ UTIME_OMIT, UTIME_NOW } case *****" 343run_test -W "" 400 "" "0 o 0 n" SUCCESS n y 344 345echo "***** Testing times=={ x, y } case *****" 346run_test -W "" 400 "" "1 1 1 1" SUCCESS y y 347 348echo "============================================================" 349 350echo 351echo "Testing read-only file, not owned by self" 352echo 353 354echo "***** Testing times==NULL case *****" 355run_test -RW root 400 "" "" EACCES 356 357echo "***** Testing times=={ UTIME_NOW, UTIME_NOW } case *****" 358run_test -RW root 400 "" "0 n 0 n" EACCES 359 360echo "***** Testing times=={ UTIME_OMIT, UTIME_OMIT } case *****" 361run_test -RW root 400 "" "0 o 0 o" SUCCESS n n 362 363echo "***** Testing times=={ UTIME_NOW, UTIME_OMIT } case *****" 364run_test -RW root 400 "" "0 n 0 o" EPERM 365 366echo "***** Testing times=={ UTIME_OMIT, UTIME_NOW } case *****" 367run_test -RW root 400 "" "0 o 0 n" EPERM 368 369echo "***** Testing times=={ x, y } case *****" 370run_test -RW root 400 "" "1 1 1 1" EPERM 371 372echo "============================================================" 373 374echo 375echo "Testing writable file, not owned by self" 376echo 377 378echo "***** Testing times==NULL case *****" 379run_test root 666 "" "" SUCCESS y y 380 381echo "***** Testing times=={ UTIME_NOW, UTIME_NOW } case *****" 382run_test root 666 "" "0 n 0 n" SUCCESS y y 383 384echo "***** Testing times=={ UTIME_OMIT, UTIME_OMIT } case *****" 385run_test root 666 "" "0 o 0 o" SUCCESS n n 386 387echo "***** Testing times=={ UTIME_NOW, UTIME_OMIT } case *****" 388run_test root 666 "" "0 n 0 o" EPERM 389 390echo "***** Testing times=={ UTIME_OMIT, UTIME_NOW } case *****" 391run_test root 666 "" "0 o 0 n" EPERM 392 393echo "***** Testing times=={ x, y } case *****" 394run_test root 666 "" "1 1 1 1" EPERM 395 396echo "============================================================" 397 398echo 399echo "Testing append-only file, owned by self" 400echo 401 402echo "***** Testing times==NULL case *****" 403run_test "" 600 "+a" "" SUCCESS y y 404 405echo "***** Testing times=={ UTIME_NOW, UTIME_NOW } case *****" 406run_test "" 600 "+a" "0 n 0 n" SUCCESS y y 407 408echo "***** Testing times=={ UTIME_OMIT, UTIME_OMIT } case *****" 409run_test "" 600 "+a" "0 o 0 o" SUCCESS n n 410 411echo "***** Testing times=={ UTIME_NOW, UTIME_OMIT } case *****" 412run_test "" 600 "+a" "0 n 0 o" EPERM 413 414echo "***** Testing times=={ UTIME_OMIT, UTIME_NOW } case *****" 415run_test "" 600 "+a" "0 o 0 n" EPERM 416 417echo "***** Testing times=={ x, y } case *****" 418run_test "" 600 "+a" "1 1 1 1" EPERM 419 420echo "============================================================" 421 422echo 423echo "Testing immutable file, owned by self" 424echo 425 426echo "***** Testing times==NULL case *****" 427run_test -W "" 600 "+i" "" $imaccess 428 429echo "***** Testing times=={ UTIME_NOW, UTIME_NOW } case *****" 430run_test -W "" 600 "+i" "0 n 0 n" $imaccess 431 432echo "***** Testing times=={ UTIME_OMIT, UTIME_OMIT } case *****" 433run_test -W "" 600 "+i" "0 o 0 o" SUCCESS n n 434 435echo "***** Testing times=={ UTIME_NOW, UTIME_OMIT } case *****" 436run_test -W "" 600 "+i" "0 n 0 o" EPERM 437 438echo "***** Testing times=={ UTIME_OMIT, UTIME_NOW } case *****" 439run_test -W "" 600 "+i" "0 o 0 n" EPERM 440 441echo "***** Testing times=={ x, y } case *****" 442run_test -W "" 600 "+i" "1 1 1 1" EPERM 443 444echo "============================================================" 445 446# Immutable+append-only should have same results as immutable 447 448echo 449echo "Testing immutable append-only file, owned by self" 450echo 451 452echo "***** Testing times==NULL case *****" 453run_test -W "" 600 "+ai" "" $imaccess 454 455echo "***** Testing times=={ UTIME_NOW, UTIME_NOW } case *****" 456run_test -W "" 600 "+ai" "0 n 0 n" $imaccess 457 458echo "***** Testing times=={ UTIME_OMIT, UTIME_OMIT } case *****" 459run_test -W "" 600 "+ai" "0 o 0 o" SUCCESS n n 460 461echo "***** Testing times=={ UTIME_NOW, UTIME_OMIT } case *****" 462run_test -W "" 600 "+ai" "0 n 0 o" EPERM 463 464echo "***** Testing times=={ UTIME_OMIT, UTIME_NOW } case *****" 465run_test -W "" 600 "+ai" "0 o 0 n" EPERM 466 467echo "***** Testing times=={ x, y } case *****" 468run_test -W "" 600 "+ai" "1 1 1 1" EPERM 469 470echo "============================================================" 471 472echo 473 474# EINVAL should result, if pathname is NULL, dirfd is not 475# AT_FDCWD, and flags contains AT_SYMLINK_NOFOLLOW. 476 477echo "***** Testing pathname==NULL, dirfd!=AT_FDCWD, flags has" \ 478 "AT_SYMLINK_NOFOLLOW *****" 479setup_file $FILE "" 600 "" 480CMD="$TEST_PROG -q -n -d $FILE NULL $4" 481echo "$CMD" 482$CMD > $RESULT_FILE 483check_result $? EINVAL 484echo 485 486echo "============================================================" 487 488echo 489 490# If UTIME_NOW / UTIME_OMIT in tv_nsec field, the tv_sec should 491# be ignored. 492 493echo "tv_sec should be ignored if tv_nsec is UTIME_OMIT or UTIME_NOW" 494 495echo "***** Testing times=={ UTIME_NOW, UTIME_NOW } case *****" 496run_test -RW "" 600 "" "1 n 1 n" SUCCESS y y 497 498echo "***** Testing times=={ UTIME_OMIT, UTIME_OMIT } case *****" 499run_test -RW "" 600 "" "1 o 1 o" SUCCESS n n 500 501echo "============================================================" 502 503echo 504 505rm -rf "$TEST_DIR" 506uname -a 507date 508echo "Total tests: $test_num; passed: $passed_cnt; failed: $failed_cnt" 509if test $failed_cnt -gt 0; then 510 echo "Failed tests: $failed_list" 511fi 512 513tst_exit 514