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 while ! test -e "testlock"; do 51 sleep 0.1 52 done 53 54 # Attempt both verbose and silent re-lock 55 atf_check -s exit:${EX_TEMPFAIL} -e not-empty \ 56 lockf -t 0 "testlock" sleep 0 57 atf_check -s exit:${EX_TEMPFAIL} -e empty \ 58 lockf -t 0 -s "testlock" sleep 0 59 60 # Make sure it cleans up after the initial sleep 10 is over. 61 wait "$lpid" 62 atf_check test ! -e "testlock" 63} 64 65atf_test_case fdlock 66fdlock_body() 67{ 68 # First, make sure we don't get a false positive -- existing uses with 69 # numeric filenames shouldn't switch to being fdlocks automatically. 70 atf_check lockf -k "9" sleep 0 71 atf_check test -e "9" 72 rm "9" 73 74 subexit_lockfail=1 75 subexit_created=2 76 subexit_lockok=3 77 subexit_concurrent=4 78 ( 79 lockf -s -t 0 9 80 if [ $? -ne 0 ]; then 81 exit "$subexit_lockfail" 82 fi 83 84 if [ -e "9" ]; then 85 exit "$subexit_created" 86 fi 87 ) 9> "testlock1" 88 rc=$? 89 90 atf_check test "$rc" -eq 0 91 92 sub_delay=5 93 94 # But is it actually locking? Child 1 will acquire the lock and then 95 # signal that it's ok for the second child to try. The second child 96 # will try to acquire the lock and fail immediately, signal that it 97 # tried, then try again with an indefinite timeout. On that one, we'll 98 # just check how long we ended up waiting -- it should be at least 99 # $sub_delay. 100 ( 101 lockf -s -t 0 /dev/fd/9 102 if [ $? -ne 0 ]; then 103 exit "$subexit_lockfail" 104 fi 105 106 # Signal 107 touch ".lock_acquired" 108 109 while [ ! -e ".lock_attempted" ]; do 110 sleep 0.5 111 done 112 113 sleep "$sub_delay" 114 115 if [ -e ".lock_acquired_again" ]; then 116 exit "$subexit_concurrent" 117 fi 118 ) 9> "testlock2" & 119 lpid1=$! 120 121 ( 122 while [ ! -e ".lock_acquired" ]; do 123 sleep 0.5 124 done 125 126 # Got the signal, try 127 lockf -s -t 0 9 128 if [ $? -ne "${EX_TEMPFAIL}" ]; then 129 exit "$subexit_lockok" 130 fi 131 132 touch ".lock_attempted" 133 start=$(date +"%s") 134 lockf -s 9 135 touch ".lock_acquired_again" 136 now=$(date +"%s") 137 elapsed=$((now - start)) 138 139 if [ "$elapsed" -lt "$sub_delay" ]; then 140 exit "$subexit_concurrent" 141 fi 142 ) 9> "testlock2" & 143 lpid2=$! 144 145 wait "$lpid1" 146 status1=$? 147 148 wait "$lpid2" 149 status2=$? 150 151 atf_check test "$status1" -eq 0 152 atf_check test "$status2" -eq 0 153} 154 155atf_test_case keep 156keep_body() 157{ 158 lockf -k "testlock" sleep 10 & 159 lpid=$! 160 161 # Make sure that the lock exists now... 162 while ! test -e "testlock"; do 163 sleep 0.5 164 done 165 166 kill "$lpid" 167 wait "$lpid" 168 169 # And it still exits after the lock has been relinquished. 170 atf_check test -e "testlock" 171} 172 173atf_test_case needfile 174needfile_body() 175{ 176 # Hopefully the clock doesn't jump. 177 start=$(date +"%s") 178 179 # Should fail if the lockfile does not yet exist. 180 atf_check -s exit:"${EX_UNAVAILABLE}" lockf -sn "testlock" sleep 30 181 182 # It's hard to guess how quickly we should have finished that; one would 183 # hope that it exits fast, but to be safe we specified a sleep 30 under 184 # lock so that we have a good margin below that duration that we can 185 # safely test to make sure we didn't actually execute the program, more 186 # or less. 187 now=$(date +"%s") 188 tpass=$((now - start)) 189 atf_check test "$tpass" -lt 10 190} 191 192atf_test_case timeout 193timeout_body() 194{ 195 lockf "testlock" sleep 30 & 196 lpid=$! 197 198 while ! test -e "testlock"; do 199 sleep 0.5 200 done 201 202 start=$(date +"%s") 203 timeout=2 204 atf_check -s exit:${EX_TEMPFAIL} lockf -st "$timeout" "testlock" sleep 0 205 206 # We should have taken no less than our timeout, at least. 207 now=$(date +"%s") 208 tpass=$((now - start)) 209 atf_check test "$tpass" -ge "$timeout" 210 211 kill "$lpid" 212 wait "$lpid" || true 213} 214 215atf_test_case wrlock 216wrlock_head() 217{ 218 atf_set "require.user" "unprivileged" 219} 220wrlock_body() 221{ 222 touch "testlock" 223 chmod -w "testlock" 224 225 # Demonstrate that we can lock the file normally, but -w fails if we 226 # can't write. 227 atf_check lockf -kt 0 "testlock" sleep 0 228 atf_check -s exit:${EX_CANTCREAT} -e not-empty \ 229 lockf -wt 0 "testlock" sleep 0 230} 231 232atf_init_test_cases() 233{ 234 atf_add_test_case badargs 235 atf_add_test_case basic 236 atf_add_test_case fdlock 237 atf_add_test_case keep 238 atf_add_test_case needfile 239 atf_add_test_case timeout 240 atf_add_test_case wrlock 241} 242