diff --git a/ccollect b/ccollect index 5454f51..20498b2 100755 --- a/ccollect +++ b/ccollect @@ -54,6 +54,67 @@ CDATE="date +%Y%m%d-%H%M" DDATE="date +%Y-%m-%d-%H:%M:%S" SDATE="date +%s" +# +# LOCKING: use flock if available, otherwise mkdir +# Locking is done for each source so that only one instance per source +# can run. +# +LOCKDIR="${CSOURCES}" +# printf pattern: ccollect_.lock +LOCKFILE_PATTERN="ccollect_%s.lock" +LOCKFD=4 + +# +# locking functions using flock +# +lock_flock() +{ + # $1 = source to backup + lockfile="${LOCKDIR}/$(printf "${LOCKFILE_PATTERN}" "$1")" + eval "exec ${LOCKFD}> ${lockfile}" + + flock -n ${LOCKFD} && return 0 || return 1 +} + +unlock_flock() +{ + # $1 = source to backup + lockfile="${LOCKDIR}/$(printf "${LOCKFILE_PATTERN}" "$1")" + eval "exec ${LOCKFD}>&-" + rm -f "${lockfile}" +} + +# +# locking functions using mkdir (mkdir is atomic) +# +lock_mkdir() +{ + # $1 = source to backup + lockfile="${LOCKDIR}/$(printf "${LOCKFILE_PATTERN}" "$1")" + + mkdir "${lockfile}" && return 0 || return 1 +} + +unlock_mkdir() +{ + # $1 = source to backup + lockfile="${LOCKDIR}/$(printf "${LOCKFILE_PATTERN}" "$1")" + + rmdir "${lockfile}" +} + +# +# determine locking tool: flock or mkdir +# +if $(which flock > /dev/null 2>&1) +then + lockf="lock_flock" + unlockf="unlock_flock" +else + lockf="lock_mkdir" + unlockf="unlock_mkdir" +fi + # # unset values # @@ -63,7 +124,8 @@ USE_ALL="" # # catch signals # -trap "rm -f \"${TMP}\"" 1 2 15 +TRAPFUNC="rm -f \"${TMP}\"" +trap "${TRAPFUNC}" 1 2 15 # # Functions @@ -136,6 +198,18 @@ eof exit 0 } +# locking functions +lock() +{ + "${lockf}" "$@" || _exit_err \ + "Only one instance of ${__myname} for source \"$1\" can run at one time." +} + +unlock() +{ + "${unlockf}" "$@" +} + # # Parse options # @@ -287,6 +361,16 @@ while [ "${source_no}" -lt "${no_sources}" ]; do _exit_err "\"${backup}\" is not a cconfig-directory. Skipping." fi + # + # Acquire lock for source. If lock cannot be acquired, lock will exit + # with error message. + # + lock "${name}" + + # redefine trap to also unlock (rm lockfile) + TRAPFUNC="${TRAPFUNC} && unlock \"${name}\"" + trap "${TRAPFUNC}" 1 2 15 + # # First execute pre_exec, which may generate destination or other parameters # @@ -561,4 +645,5 @@ if [ -x "${CPOSTEXEC}" ]; then fi rm -f "${TMP}" +unlock "${name}" _techo "Finished" diff --git a/doc/changes/next b/doc/changes/next index e865dff..05c1a37 100644 --- a/doc/changes/next +++ b/doc/changes/next @@ -1,3 +1,4 @@ + * Add locking (Darko Poljak) * Fix source-is-up check (Nikita Koshikov) * Fix some minor command line parsing issues (Nico Schottelius) * Correct output, if configuration is not in cconfig format (Nico Schottelius)