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