| #!/bin/bash | |
| # This file is part of util-linux. | |
| # | |
| # This file is free software; you can redistribute it and/or modify | |
| # it under the terms of the GNU General Public License as published by | |
| # the Free Software Foundation; either version 2 of the License, or | |
| # (at your option) any later version. | |
| # | |
| # This file is distributed in the hope that it will be useful, | |
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| # GNU General Public License for more details. | |
| TS_TOPDIR="${0%/*}/../.." | |
| TS_DESC="flock" | |
| . $TS_TOPDIR/functions.sh | |
| ts_init "$*" | |
| ts_check_test_command "$TS_CMD_FLOCK" | |
| ts_check_prog "pgrep" | |
| ts_check_prog "timeout" | |
| function do_lock { | |
| local opts="$1" | |
| local expected_rc="$2" | |
| local mesg="$3" | |
| $TS_CMD_FLOCK $1 $TS_OUTDIR/lockfile \ | |
| echo "$mesg" \ | |
| > $TS_OUTPUT 2>&1 | |
| local rc="$?" | |
| if [ "$rc" == "$expected_rc" ]; then | |
| ts_log "Success" | |
| else | |
| ts_log "Failed [rc=$rc]" | |
| fi | |
| } | |
| # general lock | |
| GEN_OUTPUT="$TS_OUTPUT" | |
| START=$(date '+%s') | |
| # running flock in background is not the best usage example | |
| $TS_CMD_FLOCK --shared $TS_OUTDIR/lockfile \ | |
| bash -c 'echo "Locking"; sleep 3; echo "Unlocking"' \ | |
| > $GEN_OUTPUT 2>&1 & | |
| pid=$! | |
| # check for running background process | |
| if [ "$pid" -le "0" ] || ! kill -s 0 "$pid" &>/dev/null; then | |
| ts_die "unable to run flock" | |
| fi | |
| # the lock should be established when flock has a child | |
| timeout 1s bash -c "while ! pgrep -P $pid >/dev/null; do sleep 0.1 ;done" \ | |
| || ts_die "timeout waiting for flock child" | |
| ts_init_subtest "non-block" | |
| do_lock "--nonblock --conflict-exit-code 123" 123 "You will never see this!" | |
| ts_finalize_subtest | |
| ts_init_subtest "no-fork" | |
| do_lock "--no-fork --nonblock --conflict-exit-code 123" 123 "You will never see this!" | |
| ts_finalize_subtest | |
| ts_init_subtest "shared" | |
| do_lock "--shared" 0 "Have shared lock" | |
| ts_finalize_subtest | |
| # this is the same as non-block test (exclusive lock is the default), but here | |
| # we explicitly specify --exclusive on command line | |
| ts_init_subtest "exclusive" | |
| do_lock "--nonblock --exclusive --conflict-exit-code 123" 123 "You will never see this!" | |
| ts_finalize_subtest | |
| ts_init_subtest "timeout" | |
| do_lock "--timeout 5 --conflict-exit-code 5" 0 "After timeout." | |
| END=$(date '+%s') | |
| ts_finalize_subtest | |
| # expected is 3 seconds (see "sleep 3" for the general lock), but we should not | |
| # rely on exact number due to scheduler, machine load, etc. Let's check for | |
| # inmterval <3,5>. | |
| # | |
| ts_init_subtest "time-check" | |
| TIMEDIFF=$(( $END - $START )) | |
| if [ $TIMEDIFF -lt 3 ]; then | |
| ts_log "general lock failed [$TIMEDIFF sec]" | |
| elif [ $TIMEDIFF -gt 5 ]; then | |
| ts_log "wait too long [$TIMEDIFF sec]" | |
| else | |
| ts_log "success" | |
| fi | |
| ts_finalize_subtest "diff ${TIMEDIFF} sec" | |
| echo "Unlocked" >> $GEN_OUTPUT | |
| ts_finalize |