2 # Trigger a failed assertion in coreutils-8.9 and earlier.
4 # Copyright (C) 2011-2018 Free Software Foundation, Inc.
6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <https://www.gnu.org/licenses/>.
19 .
"${srcdir=.}/tests/init.sh"; path_prepend_ .
/src
23 # We use a python-inotify script, so...
24 python
-m pyinotify
-h > /dev
/null \
25 || skip_
'python inotify package not installed'
27 # Move a directory "up" while du is processing its sub-directories.
28 # While du is processing a hierarchy .../B/C/D/... this script
29 # detects when du opens D/, and then moves C/ "up" one level
30 # so that it is a sibling of B/.
31 # Given the inherent race condition, we have to add enough "weight"
32 # under D/ so that in most cases, the monitor performs the single
33 # rename syscall before du finishes processing the subtree under D/.
35 cat <<'EOF' > inotify-watch-for-dir-access.py
37 import pyinotify as pn
41 dest_parent = os.path.dirname(os.path.dirname(dir))
42 dest = os.path.join(dest_parent, os.path.basename(dir))
44 class ProcessDir(pn.ProcessEvent):
46 def process_IN_OPEN(self, event):
50 def process_default(self, event):
53 wm = pn.WatchManager()
54 notifier = pn.Notifier(wm)
55 wm.watch_transient_file(dir, pn.IN_OPEN, ProcessDir)
56 sys.stdout.write('started\n')
60 chmod a
+x inotify-watch-for-dir-access.py
63 mkdir d2 || framework_failure_
64 long
=d
/e
/f
/g
/h
/i
/j
/k
/l
/m
/n
/o
/p
/q
/r
/s
/t
/u
/v
/w
/x
/y
/z
65 # One iteration of this loop creates a tree with which
66 # du sometimes completes its traversal before the above rename.
67 # Five iterations was not enough in 2 of 7 "make -j20 check" runs on a
68 # 6/12-core system. However, using "10", I saw no failure in 20 trials.
69 # Using 10 iterations was not enough, either.
70 # Using 50, I saw no failure in 200 trials.
71 for i
in $
(seq 50); do
72 mkdir
-p $t/3/a
/b
/c
/$i/$long || framework_failure_
75 # Terminate any background cp process
76 cleanup_
() { kill $pid 2>/dev
/null
&& wait $pid; }
78 # Prohibit suspension, which could otherwise cause a timeout-induced FP failure.
81 timeout
6 .
/inotify-watch-for-dir-access.py
$t/3/a
/b
> start-msg
& pid
=$
!
83 # Wait for the watcher to start...
84 nonempty
() { sleep $1; test -s start-msg
; }
85 retry_delay_ nonempty
.1 5 || fail
=1
87 # The above watches for an IN_OPEN event on $t/3/a/b,
88 # and when it triggers, moves the parent, $t/3/a, up one level
89 # so it's directly under $t.
91 # Before coreutils-8.10, du would abort.
92 returns_
1 du
-a $t d2
2> err || fail
=1
94 # check for the new diagnostic
95 printf "du: fts_read failed: $t/3/a/b: No such file or directory\n" > exp \
97 compare exp err || fail
=1