1# 2# SPDX-License-Identifier: BSD-2-Clause 3# 4# Copyright (c) 2023 Klara, Inc. 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions 8# are met: 9# 1. Redistributions of source code must retain the above copyright 10# notice, this list of conditions and the following disclaimer. 11# 2. Redistributions in binary form must reproduce the above copyright 12# notice, this list of conditions and the following disclaimer in the 13# documentation and/or other materials provided with the distribution. 14# 15# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25# SUCH DAMAGE. 26# 27 28# sysexits(3) 29: ${EX_USAGE:=64} 30: ${EX_UNAVAILABLE:=69} 31: ${EX_CANTCREAT:=73} 32: ${EX_TEMPFAIL:=75} 33 34atf_test_case badargs 35badargs_body() 36{ 37 atf_check -s exit:${EX_USAGE} -e not-empty lockf 38 atf_check -s exit:${EX_USAGE} -e not-empty lockf "testlock" 39} 40 41atf_test_case basic 42basic_body() 43{ 44 # Something innocent so that it does eventually go away without our 45 # intervention. 46 lockf "testlock" sleep 10 & 47 lpid=$! 48 49 # Make sure that the lock exists... 50 atf_check test -e "testlock" 51 52 # Attempt both verbose and silent re-lock 53 atf_check -s exit:${EX_TEMPFAIL} -e not-empty \ 54 lockf -t 0 "testlock" sleep 0 55 atf_check -s exit:${EX_TEMPFAIL} -e empty \ 56 lockf -t 0 -s "testlock" sleep 0 57 58 # Make sure it cleans up after the initial sleep 10 is over. 59 wait "$lpid" 60 atf_check test ! -e "testlock" 61} 62 63atf_test_case fdlock 64fdlock_body() 65{ 66 # First, make sure we don't get a false positive -- existing uses with 67 # numeric filenames shouldn't switch to being fdlocks automatically. 68 atf_check lockf -k "9" sleep 0 69 atf_check test -e "9" 70 rm "9" 71 72 subexit_lockfail=1 73 subexit_created=2 74 subexit_lockok=3 75 subexit_concurrent=4 76 ( 77 lockf -s -t 0 9 78 if [ $? -ne 0 ]; then 79 exit "$subexit_lockfail" 80 fi 81 82 if [ -e "9" ]; then 83 exit "$subexit_created" 84 fi 85 ) 9> "testlock1" 86 rc=$? 87 88 atf_check test "$rc" -eq 0 89 90 sub_delay=5 91 92 # But is it actually locking? Child 1 will acquire the lock and then 93 # signal that it's ok for the second child to try. The second child 94 # will try to acquire the lock and fail immediately, signal that it 95 # tried, then try again with an indefinite timeout. On that one, we'll 96 # just check how long we ended up waiting -- it should be at least 97 # $sub_delay. 98 ( 99 lockf -s -t 0 /dev/fd/9 100 if [ $? -ne 0 ]; then 101 exit "$subexit_lockfail" 102 fi 103 104 # Signal 105 touch ".lock_acquired" 106 107 while [ ! -e ".lock_attempted" ]; do 108 sleep 0.5 109 done 110 111 sleep "$sub_delay" 112 113 if [ -e ".lock_acquired_again" ]; then 114 exit "$subexit_concurrent" 115 fi 116 ) 9> "testlock2" & 117 lpid1=$! 118 119 ( 120 while [ ! -e ".lock_acquired" ]; do 121 sleep 0.5 122 done 123 124 # Got the signal, try 125 lockf -s -t 0 9 126 if [ $? -ne "${EX_TEMPFAIL}" ]; then 127 exit "$subexit_lockok" 128 fi 129 130 touch ".lock_attempted" 131 start=$(date +"%s") 132 lockf -s 9 133 touch ".lock_acquired_again" 134 now=$(date +"%s") 135 elapsed=$((now - start)) 136 137 if [ "$elapsed" -lt "$sub_delay" ]; then 138 exit "$subexit_concurrent" 139 fi 140 ) 9> "testlock2" & 141 lpid2=$! 142 143 wait "$lpid1" 144 status1=$? 145 146 wait "$lpid2" 147 status2=$? 148 149 atf_check test "$status1" -eq 0 150 atf_check test "$status2" -eq 0 151} 152 153atf_test_case keep 154keep_body() 155{ 156 lockf -k "testlock" sleep 10 & 157 lpid=$! 158 159 # Make sure that the lock exists now... 160 while ! test -e "testlock"; do 161 sleep 0.5 162 done 163 164 kill "$lpid" 165 wait "$lpid" 166 167 # And it still exits after the lock has been relinquished. 168 atf_check test -e "testlock" 169} 170 171atf_test_case needfile 172needfile_body() 173{ 174 # Hopefully the clock doesn't jump. 175 start=$(date +"%s") 176 177 # Should fail if the lockfile does not yet exist. 178 atf_check -s exit:"${EX_UNAVAILABLE}" lockf -sn "testlock" sleep 30 179 180 # It's hard to guess how quickly we should have finished that; one would 181 # hope that it exits fast, but to be safe we specified a sleep 30 under 182 # lock so that we have a good margin below that duration that we can 183 # safely test to make sure we didn't actually execute the program, more 184 # or less. 185 now=$(date +"%s") 186 tpass=$((now - start)) 187 atf_check test "$tpass" -lt 10 188} 189 190atf_test_case timeout 191timeout_body() 192{ 193 lockf "testlock" sleep 30 & 194 lpid=$! 195 196 while ! test -e "testlock"; do 197 sleep 0.5 198 done 199 200 start=$(date +"%s") 201 timeout=2 202 atf_check -s exit:${EX_TEMPFAIL} lockf -st "$timeout" "testlock" sleep 0 203 204 # We should have taken no less than our timeout, at least. 205 now=$(date +"%s") 206 tpass=$((now - start)) 207 atf_check test "$tpass" -ge "$timeout" 208 209 kill "$lpid" 210 wait "$lpid" || true 211} 212 213atf_test_case wrlock 214wrlock_head() 215{ 216 atf_set "require.user" "unprivileged" 217} 218wrlock_body() 219{ 220 touch "testlock" 221 chmod -w "testlock" 222 223 # Demonstrate that we can lock the file normally, but -w fails if we 224 # can't write. 225 atf_check lockf -kt 0 "testlock" sleep 0 226 atf_check -s exit:${EX_CANTCREAT} -e not-empty \ 227 lockf -wt 0 "testlock" sleep 0 228} 229 230atf_init_test_cases() 231{ 232 atf_add_test_case badargs 233 atf_add_test_case basic 234 atf_add_test_case fdlock 235 atf_add_test_case keep 236 atf_add_test_case needfile 237 atf_add_test_case timeout 238 atf_add_test_case wrlock 239} 240