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