Doc updates: sponsoring and volunteer info
[girocco.git] / jobd / updategc-util-functions.sh
blob12d2e72e771a4c48612c80a6e28f062748b33767
1 #!/bin/sh
3 # This is a shell library for common update/gc related functions
4 # used by various Girocco scripts.
6 # shlib.sh always sets this, it's an error to source
7 # this script without having already sourced shlib.sh
8 [ -n "$var_git_exec_path" ] || exit 2
10 pidactive() {
11 if _result="$(kill -0 "$1" 2>&1)"; then
12 # process exists and we have permission to signal it
13 return 0
15 case "$_result" in *"not permitted"*)
16 # we do not have permission to signal the process
17 return 0
18 esac
19 # process does not exist
20 return 1
23 createlock() {
24 # A .lock file should only exist for much less than a second.
25 # If we see a stale lock file (> 1h old), remove it and then,
26 # just in case, wait 30 seconds for any process whose .lock
27 # we might have just removed (it's racy) to finish doing what
28 # should take much less than a second to do.
29 _stalelock="$(find -L "$1.lock" -maxdepth 1 -mmin +60 -print 2>/dev/null)" || :
30 if [ -n "$_stalelock" ]; then
31 rm -f "$_stalelock"
32 sleep 30
34 for _try in p p n; do
35 if (set -C; >"$1.lock") 2>/dev/null; then
36 echo "$1.lock"
37 return 0
39 # delay and try again
40 [ "$_try" != "p" ] || sleep 1
41 done
42 # cannot create lock file
43 return 1
46 # Create a new lockfile
47 # $1 => name of variable to store result in
48 # $2 => name of the new lockfile (default is "lockfile.pid")
49 # $3 => "type" name to use in error message (default is ${2%%.*})
50 # On success:
51 # variable named by $1 will contain the name of the newly create lockfile (i.e. "$2")
52 # On failure:
53 # variable named by $1 will contain the failure reason
54 v_lock_file() {
55 # be compatibile with gc.pid file from newer Git releases
56 _lockf="${2:-lockfile.pid}"
57 _locktype="${3:-${2%%.*}}"
58 _hn="$(hostname)"
59 _active=
60 if [ "$(createlock "$_lockf")" ]; then
61 # If $_lockf is:
62 # 1) less than 12 hours old
63 # 2) contains two fields (pid hostname) NO trailing NL
64 # 3) the hostname is different OR the pid is still alive
65 # then we exit as another active process is holding the lock
66 if [ "$(find -L "$_lockf" -maxdepth 1 -mmin -720 -print 2>/dev/null)" ]; then
67 _apid=
68 _ahost=
69 read -r _apid _ahost _ajunk <"$_lockf" || :
70 if [ "$_apid" ] && [ "$_ahost" ]; then
71 if [ "$_ahost" != "$_hn" ] || pidactive "$_apid"; then
72 _active=1
76 else
77 eval "$1="'"unable to create $_lockf.lock file"'
78 return 1
80 if [ -n "$_active" ]; then
81 rm -f "$_lockf.lock"
82 eval "$1="'"$_locktype already running on machine '\''$_ahost'\'' pid '\''$_apid'\''"'
83 return 1
85 printf "%s %s" "$$" "$_hn" >"$_lockf.lock"
86 chmod 0664 "$_lockf.lock"
87 mv -f "$_lockf.lock" "$_lockf"
88 eval "$1="'"$_lockf"'
89 return 0
92 # duplicate the first file to the name given by the second file making sure that
93 # the second file appears atomically all-at-once after the copy has been completed
94 # and does not appear at all if the copy fails (in which case this function fails)
95 # if the second file already exists this function fails with status 1
96 # if the file names are the same this function returns immediately with success
97 # the optional third argument specifies the temp file prefix (default is "packtmp-")
98 dupe_file() {
99 [ "$1" != "$2" ] || return 0
100 ! [ -e "$2" ] || return 1
101 case "$2" in
102 *?/?*) _tmpdir="${2%/*}";;
103 *) _tmpdir=".";;
104 esac
105 _tmpfile="$(mktemp "${_tmpdir:-.}/${3:-packtmp-}XXXXXX")" || return 1
106 cp -fp "$1" "$_tmpfile" || return 1
107 mv -f "$_tmpfile" "$2"
110 # rename_pack oldnamepath newnamepath
111 # note that .keep and .bndl files are left untouched and not moved at all!
112 rename_pack() {
113 [ $# -eq 2 ] && [ "$1" != "$2" ] || {
114 echo >&2 "[$proj] incorrect use of rename_pack function"
115 exit 1
117 # Git assumes that if the destination of the rename already exists
118 # that it is, in fact, a copy of the same bytes so silently succeeds
119 # without doing anything. We duplicate that logic here.
120 # Git checks for the .idx file first before even trying to use a pack
121 # so it should be the last moved and the first removed.
122 for ext in pack bitmap idx; do
123 [ -f "$1.$ext" ] || continue
124 ln "$1.$ext" "$2.$ext" >/dev/null 2>&1 ||
125 dupe_file "$1.$ext" "$2.$ext" >/dev/null 2>&1 ||
126 [ -f "$2.$ext" ] || {
127 echo >&2 "[$proj] unable to move $1.$ext to $2.$ext"
128 exit 1
130 done
131 for ext in idx pack bitmap; do
132 rm -f "$1.$ext"
133 done
134 return 0