Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env sh
- # NAME lock
- # PURPOSE library for provides two types of lock and a related exit routine.
- # FROM Parts adapted from:
- # www.kfirlavi.com/blog/2012/11/06/elegant-locking-of-bash-program
- # NEEDS ** dash **
- # USAGE See separate (documentation) file.
- readonly lock_logLvl=0
- # ^ 0: off. 1: minimal. 2: full. Some errors get logged even if the value is 0.
- readonly lock_lockFile_dir='/tmp'
- # ^ Setting this to a *subfolder* of tmp stops things working, for some reason.
- readonly lock_fd=9
- # ^ Highest value of lock_fd supported by *Dash* is 9 (but 200 for Bash?).
- lock_file_lock_core() {
- lock_isUnset=${lock_lockFile_handle:-}
- if [ -z "${lock_isUnset}" ]; then
- lock_log 'Handle variable is undefined!'
- return 1
- fi
- [ ${lock_logLvl} -gt 1 ] &&
- lock_log "Trying to lock with file <${lock_lockFile}>: creating file .."
- # The stuff below somehow 'uses an open file by its file descriptor number'
- # - according to 'man flock'.
- lock_loop=1
- lock_loopMax=3
- while [ ${lock_loop} -le ${lock_loopMax} ]; do
- /usr/bin/flock -n "${lock_lockFile_handle}" >/dev/null 2>&1 &&
- return 0
- sleep 0.25
- lock_loop=$((lock_loop + 1))
- done
- [ -e "${lock_lockFile}" ] && return 0
- case ${lock_logLvl} in
- 0)
- lock_log \
- "Problem: Could not create lock file <${lock_lockFile}>, though file does not exist already."
- ;;
- *)
- lock_log \
- "Problem: Could not create lock file <${lock_lockFile}>; and lock file exists already."
- ;;
- esac
- return 1
- }
- # ${1}
- lock_log() {
- case $# in
- 1)
- lock_msg="Lock library: ${1}"
- ;;
- *)
- lock_msg="Function <lock_log> needs exactly one argument but $# received"
- ;;
- esac
- logger -t "${lock_progName}" "${lock_msg}"
- return 0
- }
- # ${1}
- lock_log_error() {
- case $# in
- 1)
- lock_msg="Lock library: ERROR - ${1}"
- ;;
- *)
- lock_msg="META-ERROR: function <lock_log_error> needs exactly one argument but $# received"
- ;;
- esac
- logger -t "${lock_progName}" "${lock_msg}"
- return 0
- }
- # On some stuff in here, see:
- # https://old.reddit.com/r/commandline/comments/9lwvu1/a_few_lines_to_convert_from_bash_to_dash/
- # https://unix.stackexchange.com/questions/368159/why-flock-doesnt-clean-the-lock-file
- lock_file_lock() {
- case ${lock_logLvl} in
- 0) ;;
- *)
- [ ${lock_logLvl} -eq 2 ] && lock_log 'function <lock_file_lock> - starting ..'
- lock_log \
- "function <lock_file_lock> - lock_lockFile_dir is <${lock_lockFile_dir}>. lock_userName is <${lock_userName}>. lock_progName is <${lock_progName}>"
- ;;
- esac
- # Create lock file
- lock_lockFile="${lock_lockFile_dir}/${lock_userName}-${lock_progName}.lock"
- lock_lockFile_handle="${lock_fd}"
- if eval "exec ${lock_lockFile_handle}> \"\${lock_lockFile}\""; then
- chmod 777 "${lock_lockFile}"
- lock_file_lock_core ||
- return 1
- # NB: 'lock_file_lock_core || return 1' is vital: it is what tells the calling script that the file is locked.
- [ "${lock_logLvl}" -gt 1 ] &&
- lock_log \
- "function <lock_file_lock> - finished creating lock file <${lock_lockFile}>"
- return 0
- fi
- lock_log \
- 'function <lock_file_lock> - failed to create lock-file'
- return 1
- }
- lock_file_unlock() {
- lock_isUnset=${lock_lockFile_handle:-}
- if [ -z "${lock_isUnset}" ]; then
- lock_log \
- 'function <lock_file_unlock> - lock_lockFile_handle unset!'
- return 1
- fi
- # Try to unlock the file.
- if /usr/bin/flock -u "${lock_lockFile_handle}" >/dev/null 2>&1; then
- [ ${lock_logLvl} -gt 0 ] &&
- lock_log \
- "function <lock_file_unlock> - unlocked <${lock_lockFile}>."
- return 0
- fi
- # Else .. try again.
- sleep 0.3
- if /usr/bin/flock -u "${lock_lockFile_handle}" >/dev/null 2>&1; then
- [ ${lock_logLvl} -gt 0 ] &&
- lock_log \
- "function <lock_file_unlock> - unlocked <${lock_lockFile}> (on second attempt)"
- return 0
- fi
- lock_log_error 'function <lock_file_unlock> - failed to unlock!'
- return 1
- }
- lock_file_exitCleanly() {
- lock_file_unlock
- exit 0
- }
- lock_file_exitDirtily() {
- lock_file_unlock
- exit 1
- }
- isInteger() {
- case ${1#[+-]} in
- *[!0123456789]*) return 1 ;;
- '') return 1 ;;
- *) return 0 ;;
- esac
- }
- # $1: exit code
- lock_file_exit_withCode() {
- case $# in
- 1)
- # shellcheck disable=2086
- isInteger "${1}" &&
- exit ${1}
- lock_log_error \
- 'function <lock_file_exit_withCode> - non-integer exit-code received'
- exit 1
- ;;
- *)
- lock_log_error \
- "function <lock_file_exit_withCode> needs exactly one argument but $# received"
- lock_file_unlock
- exit 1
- ;;
- esac
- }
- # $1: time period in seconds.
- # If the lock file was created fewer than $1 seconds from now, then
- # the returns true (/0).
- # If the lock file was NOT created fewer than $1 seconds from now, or does not exist,
- # then the returns false (/1).
- lock_time_ageIsLessThan() {
- case $# in
- 1) ;;
- *)
- lock_log_error \
- "function <lock_time_ageIsLessThan> needs exactly one argument but $# received"
- return 0
- ;;
- esac
- if ! isInteger "${1}"; then
- lock_log_error \
- 'function <lock_time_ageIsLessThan> - non-integer argument. Exiting'
- exit 1
- fi
- lock_timeLock_seconds=${1}
- # If use 'lock_timeLock_seconds', get a warning about bash.
- # DO THE LOCK CHECK
- lock_timeLock_file_fullPath="${lock_lockFile_dir}/${lock_userName}-${lock_progName}.timelock"
- # If the file does not exist, return false (i.e. 1)
- # which, here is the 'proceed' value.
- if ! [ -e "${lock_timeLock_file_fullPath}" ]; then
- lock_log_error \
- "function <lock_time_ageIsLessThan> - file <${lock_timeLock_file_fullPath}> does not exist"
- return 1
- fi
- # File does exist; get its date.
- if ! lock_time_timeStamp=$(stat -c%Y "${lock_timeLock_file_fullPath}"); then
- lock_log_error \
- "function <lock_time_ageIsLessThan> - could not stat file <${lock_timeLock_file_fullPath}>"
- return 1
- fi
- # Now calculate the file's age.
- lock_timeLock_now=$(date '+%s')
- if [ $((lock_timeLock_now - lock_time_timeStamp)) -lt "${lock_timeLock_seconds}" ]; then
- [ "${lock_logLvl}" -gt 1 ] &&
- lock_log \
- "function <lock_time_ageIsLessThan> - queried <${lock_timeLock_file_fullPath}> and found it fewer than <${lock_timeLock_seconds}> seconds old"
- # Return 0 / true
- return 0
- fi
- # Otherwise
- [ ${lock_logLvl} -gt 1 ] &&
- lock_log \
- "function <lock_time_ageIsLessThan> - queried ${lock_timeLock_file_fullPath}: it is at least <${lock_timeLock_seconds}> seconds old"
- if rm -f "${lock_timeLock_file_fullPath}" >/dev/null 2>&1; then
- [ ${lock_logLvl} -gt 0 ] &&
- lock_log \
- "function <lock_time_ageIsLessThan> - deleted <${lock_timeLock_file_fullPath}>"
- return 1
- fi
- lock_log_error \
- "function <lock_time_ageIsLessThan> - problem deleting <${lock_timeLock_file_fullPath}>"
- return 1
- }
- lock_time_lock() {
- lock_lockFile="${lock_lockFile_dir}/${lock_userName}-${lock_progName}.lock"
- lock_timeLock_file_fullPath="${lock_lockFile_dir}/${lock_userName}-${lock_progName}.timelock"
- if ! touch "${lock_timeLock_file_fullPath}" >/dev/null 2>&1; then
- lock_log_error \
- "function <lock_time_lock> - problem creating <${lock_timeLock_file_fullPath}>"
- return 1
- fi
- [ ${lock_logLvl} -gt 1 ] &&
- lock_log \
- "function <lock_time_lock> - created or updated <${lock_timeLock_file_fullPath}>"
- chmod 777 "${lock_timeLock_file_fullPath}" >/dev/null 2>&1 &&
- return 0
- lock_log_error \
- "function <lock_time_lock> - problem setting permissions for <${lock_timeLock_file_fullPath}>"
- return 1
- }
- lock_time_file_delete() {
- if rm -f --one-file-system -- "${lock_timeLock_file_fullPath}" >/dev/null 2>&1; then
- [ ${lock_logLvl} -gt 0 ] &&
- lock_log \
- "function <lock_time_file_delete> - ${lock_progName} deleted <${lock_timeLock_file_fullPath}>"
- return 0
- fi
- lock_log_error \
- "function <lock_time_file_delete> - problem deleting <${lock_timeLock_file_fullPath}>"
- return 1
- }
- lock_time_unlock() {
- vars_set_timeLockVar &&
- lock_time_file_delete &&
- return 0
- return 1
- }
- # AUTOEXECUTE
- lock_progName=$(basename "${0}") || lock_progName='unknown'
- if /usr/bin/test "$(id -u)" -eq "0"; then
- lock_userName='root'
- else
- lock_isUnset=${USER:-}
- if [ -z "${lock_isUnset}" ]; then
- lock_userName='unknownUser'
- else
- lock_userName="${USER}"
- fi
- fi
- # EOF
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement