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