1 #!/bin/sh 2 # 3 # Automated tests for utimensat() 4 # 5 # Copyright (C) 2008, Linux Foundation 6 # Written by Michael Kerrisk <mtk.manpages (at] 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 24 export TCID=utimensat01 25 export TST_TOTAL=99 26 export TST_COUNT=0 27 . test.sh 28 29 if tst_kvcmp -lt "2.6.22"; then 30 tst_brkm TCONF "System kernel version is less than 2.6.22,cannot execute test" 31 fi 32 33 # Starting with 4.8.0 operations on immutable files return EPERM instead of 34 # EACCES. 35 if tst_kvcmp -lt "4.8.0"; then 36 imaccess=EACCES 37 else 38 imaccess=EPERM 39 fi 40 41 42 RESULT_FILE=$TMPDIR/utimensat.result 43 44 TEST_DIR=$TMPDIR/utimensat_tests 45 FILE=$TEST_DIR/utimensat.test_file 46 47 TEST_PROG=utimensat01 48 49 if [ ! -f $LTPROOT/testcases/bin/$TEST_PROG ]; then 50 tst_brkm TWARN "$LTPROOT/testcases/bin/$TEST_PROG is missing (please check install)" 51 fi 52 53 # Summary counters of all test results 54 55 test_num=0 56 failed_cnt=0 57 passed_cnt=0 58 failed_list="" 59 60 #===================================================================== 61 62 setup_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 115 test_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 123 check_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 190 run_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. 262 sudoers=/etc/sudoers 263 if [ ! -r $sudoers ]; then 264 tst_brkm TBROK "can't read $sudoers" 265 fi 266 pattern="[[:space:]]*Defaults[[:space:]]*requiretty.*" 267 if 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 273 fi 274 275 restore_sudoers() 276 { 277 tst_resm TINFO "Restore requiretty in $sudoers" 278 mv /etc/sudoers.$$ /etc/sudoers 279 } 280 281 test_user=nobody 282 echo "test sudo for -n option, non-interactive" 283 if sudo -h | grep -q -- -n; then 284 s_arg="-n" 285 echo "sudo supports -n" 286 else 287 s_arg= 288 echo "sudo does not support -n" 289 fi 290 291 if ! sudo $s_arg true; then 292 tst_brkm TBROK "sudo cannot be run by user non-interactively" 293 fi 294 if test ! -f $sudoers 295 then 296 echo "root ALL=(ALL) ALL" > $sudoers || exit 297 chmod 440 $sudoers 298 trap 'trap "" EXIT; nuke_sudoers' EXIT 299 fi 300 301 nuke_sudoers() 302 { 303 sudo rm -f $sudoers 304 } 305 306 sudo $s_arg -u $test_user mkdir -p $TEST_DIR 307 308 # Make sure chattr command is supported 309 touch $TEST_DIR/tmp_file 310 chattr +a $TEST_DIR/tmp_file 311 if [ $? -ne 0 ] ; then 312 rm -rf $TEST_DIR 313 tst_brkm TCONF "chattr not supported" 314 fi 315 chattr -a $TEST_DIR/tmp_file 316 317 cd $TEST_DIR 318 chown root $LTPROOT/testcases/bin/$TEST_PROG 319 chmod ugo+x,u+s $LTPROOT/testcases/bin/$TEST_PROG 320 321 #===================================================================== 322 323 324 echo "============================================================" 325 326 echo 327 echo "Testing read-only file, owned by self" 328 echo 329 330 echo "***** Testing times==NULL case *****" 331 run_test -W "" 400 "" "" SUCCESS y y 332 333 echo "***** Testing times=={ UTIME_NOW, UTIME_NOW } case *****" 334 run_test -W "" 400 "" "0 n 0 n" SUCCESS y y 335 336 echo "***** Testing times=={ UTIME_OMIT, UTIME_OMIT } case *****" 337 run_test -W "" 400 "" "0 o 0 o" SUCCESS n n 338 339 echo "***** Testing times=={ UTIME_NOW, UTIME_OMIT } case *****" 340 run_test -W "" 400 "" "0 n 0 o" SUCCESS y n 341 342 echo "***** Testing times=={ UTIME_OMIT, UTIME_NOW } case *****" 343 run_test -W "" 400 "" "0 o 0 n" SUCCESS n y 344 345 echo "***** Testing times=={ x, y } case *****" 346 run_test -W "" 400 "" "1 1 1 1" SUCCESS y y 347 348 echo "============================================================" 349 350 echo 351 echo "Testing read-only file, not owned by self" 352 echo 353 354 echo "***** Testing times==NULL case *****" 355 run_test -RW root 400 "" "" EACCES 356 357 echo "***** Testing times=={ UTIME_NOW, UTIME_NOW } case *****" 358 run_test -RW root 400 "" "0 n 0 n" EACCES 359 360 echo "***** Testing times=={ UTIME_OMIT, UTIME_OMIT } case *****" 361 run_test -RW root 400 "" "0 o 0 o" SUCCESS n n 362 363 echo "***** Testing times=={ UTIME_NOW, UTIME_OMIT } case *****" 364 run_test -RW root 400 "" "0 n 0 o" EPERM 365 366 echo "***** Testing times=={ UTIME_OMIT, UTIME_NOW } case *****" 367 run_test -RW root 400 "" "0 o 0 n" EPERM 368 369 echo "***** Testing times=={ x, y } case *****" 370 run_test -RW root 400 "" "1 1 1 1" EPERM 371 372 echo "============================================================" 373 374 echo 375 echo "Testing writable file, not owned by self" 376 echo 377 378 echo "***** Testing times==NULL case *****" 379 run_test root 666 "" "" SUCCESS y y 380 381 echo "***** Testing times=={ UTIME_NOW, UTIME_NOW } case *****" 382 run_test root 666 "" "0 n 0 n" SUCCESS y y 383 384 echo "***** Testing times=={ UTIME_OMIT, UTIME_OMIT } case *****" 385 run_test root 666 "" "0 o 0 o" SUCCESS n n 386 387 echo "***** Testing times=={ UTIME_NOW, UTIME_OMIT } case *****" 388 run_test root 666 "" "0 n 0 o" EPERM 389 390 echo "***** Testing times=={ UTIME_OMIT, UTIME_NOW } case *****" 391 run_test root 666 "" "0 o 0 n" EPERM 392 393 echo "***** Testing times=={ x, y } case *****" 394 run_test root 666 "" "1 1 1 1" EPERM 395 396 echo "============================================================" 397 398 echo 399 echo "Testing append-only file, owned by self" 400 echo 401 402 echo "***** Testing times==NULL case *****" 403 run_test "" 600 "+a" "" SUCCESS y y 404 405 echo "***** Testing times=={ UTIME_NOW, UTIME_NOW } case *****" 406 run_test "" 600 "+a" "0 n 0 n" SUCCESS y y 407 408 echo "***** Testing times=={ UTIME_OMIT, UTIME_OMIT } case *****" 409 run_test "" 600 "+a" "0 o 0 o" SUCCESS n n 410 411 echo "***** Testing times=={ UTIME_NOW, UTIME_OMIT } case *****" 412 run_test "" 600 "+a" "0 n 0 o" EPERM 413 414 echo "***** Testing times=={ UTIME_OMIT, UTIME_NOW } case *****" 415 run_test "" 600 "+a" "0 o 0 n" EPERM 416 417 echo "***** Testing times=={ x, y } case *****" 418 run_test "" 600 "+a" "1 1 1 1" EPERM 419 420 echo "============================================================" 421 422 echo 423 echo "Testing immutable file, owned by self" 424 echo 425 426 echo "***** Testing times==NULL case *****" 427 run_test -W "" 600 "+i" "" $imaccess 428 429 echo "***** Testing times=={ UTIME_NOW, UTIME_NOW } case *****" 430 run_test -W "" 600 "+i" "0 n 0 n" $imaccess 431 432 echo "***** Testing times=={ UTIME_OMIT, UTIME_OMIT } case *****" 433 run_test -W "" 600 "+i" "0 o 0 o" SUCCESS n n 434 435 echo "***** Testing times=={ UTIME_NOW, UTIME_OMIT } case *****" 436 run_test -W "" 600 "+i" "0 n 0 o" EPERM 437 438 echo "***** Testing times=={ UTIME_OMIT, UTIME_NOW } case *****" 439 run_test -W "" 600 "+i" "0 o 0 n" EPERM 440 441 echo "***** Testing times=={ x, y } case *****" 442 run_test -W "" 600 "+i" "1 1 1 1" EPERM 443 444 echo "============================================================" 445 446 # Immutable+append-only should have same results as immutable 447 448 echo 449 echo "Testing immutable append-only file, owned by self" 450 echo 451 452 echo "***** Testing times==NULL case *****" 453 run_test -W "" 600 "+ai" "" $imaccess 454 455 echo "***** Testing times=={ UTIME_NOW, UTIME_NOW } case *****" 456 run_test -W "" 600 "+ai" "0 n 0 n" $imaccess 457 458 echo "***** Testing times=={ UTIME_OMIT, UTIME_OMIT } case *****" 459 run_test -W "" 600 "+ai" "0 o 0 o" SUCCESS n n 460 461 echo "***** Testing times=={ UTIME_NOW, UTIME_OMIT } case *****" 462 run_test -W "" 600 "+ai" "0 n 0 o" EPERM 463 464 echo "***** Testing times=={ UTIME_OMIT, UTIME_NOW } case *****" 465 run_test -W "" 600 "+ai" "0 o 0 n" EPERM 466 467 echo "***** Testing times=={ x, y } case *****" 468 run_test -W "" 600 "+ai" "1 1 1 1" EPERM 469 470 echo "============================================================" 471 472 echo 473 474 # EINVAL should result, if pathname is NULL, dirfd is not 475 # AT_FDCWD, and flags contains AT_SYMLINK_NOFOLLOW. 476 477 echo "***** Testing pathname==NULL, dirfd!=AT_FDCWD, flags has" \ 478 "AT_SYMLINK_NOFOLLOW *****" 479 setup_file $FILE "" 600 "" 480 CMD="$TEST_PROG -q -n -d $FILE NULL $4" 481 echo "$CMD" 482 $CMD > $RESULT_FILE 483 check_result $? EINVAL 484 echo 485 486 echo "============================================================" 487 488 echo 489 490 # If UTIME_NOW / UTIME_OMIT in tv_nsec field, the tv_sec should 491 # be ignored. 492 493 echo "tv_sec should be ignored if tv_nsec is UTIME_OMIT or UTIME_NOW" 494 495 echo "***** Testing times=={ UTIME_NOW, UTIME_NOW } case *****" 496 run_test -RW "" 600 "" "1 n 1 n" SUCCESS y y 497 498 echo "***** Testing times=={ UTIME_OMIT, UTIME_OMIT } case *****" 499 run_test -RW "" 600 "" "1 o 1 o" SUCCESS n n 500 501 echo "============================================================" 502 503 echo 504 505 rm -rf "$TEST_DIR" 506 uname -a 507 date 508 echo "Total tests: $test_num; passed: $passed_cnt; failed: $failed_cnt" 509 if test $failed_cnt -gt 0; then 510 echo "Failed tests: $failed_list" 511 fi 512 513 tst_exit 514