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