Home | History | Annotate | Download | only in utimensat
      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