This file is indexed.

/usr/lib/bash/locks.sh is in libbash 0.9.11-2.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#               Do not run this script directly!
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
###########################################################################
# Copyright (c) 2004-2009 Hai Zaar and Gil Ran                            #
#                                                                         #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of version 3 of the GNU General Public License as       #
# published by the Free Software Foundation.                              #
#                                                                         #
###########################################################################
#
# $Date: 2009-07-27 14:38:23 +0300 (Mon, 27 Jul 2009) $
# $Author: hai-zaar $
#
# This bash library provides a set of locking tools.
# The locking is done by creating a directory named `.lock'.
# After the master-lock named `.lock' is set, a process can
# create its .lock.$$ file, and remove the master-lock.
# Each non-safe action requires a master-lock.
# Locking, unlocking, cleaning leftover locks and cleaning
# left over spin-files are non-safe action and require
# a master lock.
# Creating or removing my own spin-file and creating a
# directory that should be locked are the only actions
# done on the directory, that are considered safe.

#EXPORT=dirInitLock dirTryLock dirLock dirUnlock dirDestroyLock
#REQUIRE=

prefix=/usr
__locks_LOCKS_DIR=/tmp/.dirlocks-$USER
__locks_DEFAULT_SLEEP_TIME=0.01

__locks_ERR_DIR_IS_LOCKED=1
__locks_ERR_NO_SPIN_FILE=2
__locks_ERR_COULD_NOT_RESOLVE_DIR=3

#__locks_DEBUG_MODE=1

#############################################################
######################   FUNCTIONS   ########################
#############################################################

#
# findEffectiveDirname <DirName>
#	Finds the full path that we should lock, i.e. the effective
#	dirname we should work on.
#	This function does not change files (and therefore does not lock anything).
#	Parameters:
#		DirName -	The name of the directory we wish to lock. You can choose
#					any name if you want to
__locks_findEffectiveDirname()
{
	local DIR_NAME=$1

	# Check if it a file/dir exists
	if [ -e "$DIR_NAME" ] ; then 
		if [[ -d "$DIR_NAME" ]] ; then
			retval=$(cd "$DIR_NAME" > /dev/null 2>&1 && pwd) || \
					return ${__locks_ERR_COULD_NOT_RESOLVE_DIR}
		else
			# Get the perent directory for $DIR_NAME (full path)
			retval=$(cd $(dirname "$DIR_NAME") > /dev/null 2>&1 && pwd) || \
					return ${__locks_ERR_COULD_NOT_RESOLVE_DIR}
			# Add the basename of $DIR_NAME
			retval=$(ls -d $retval/$(basename "$DIR_NAME") 2>/dev/null) || \
					return ${__locks_ERR_COULD_NOT_RESOLVE_DIR}
		fi
		return 0
	else
		# It does not exist:
		#    Expand `\'
		#    Check that it does not contain `..' - it can be very dangerous
		while echo "$DIR_NAME" |grep -q '\\'; do DIR_NAME=$(echo "$DIR_NAME" | xargs echo); done
		echo "$DIR_NAME" | grep -q '\.\.' && return ${__locks_ERR_COULD_NOT_RESOLVE_DIR}
		retval="$DIR_NAME" && return 0
	fi

	# If we got here something's wrong
	return ${__locks_ERR_COULD_NOT_RESOLVE_DIR}
}

#
# dirInitLock <DirName> [Spin]
#	Initializes a lock for a DirName object, for current process
#	
#	Parameters:
#		DirName - 	The name of the directory we wish to lock. You can choose
#					any name if you want to - i.e It does not have to be a real dir
#		Spin	-	Spin period - we'll retry to acquire lock each Spin seconds.
#					Spin may (and generally should) be less then 1. 
#					Default Spin is 0.01 seconds.
#	Return value:
#		0 - The lock was initialized and is ready for use
#		non-zero - The lock was not initialized
#
dirInitLock()
{
	local DIR_NAME=$1
	local SPIN=${2:-${__locks_DEFAULT_SLEEP_TIME}}
	
	# Resolve effective directory name
	__locks_findEffectiveDirname "$DIR_NAME" || return ${__locks_ERR_COULD_NOT_RESOLVE_DIR}
	local EFFECTIVE_DIRNAME=$retval

	__locks_setMasterLock "${__locks_LOCKS_DIR}/$EFFECTIVE_DIRNAME"

	__locks_spinCleanup "$DIR_NAME"

	# Creating our spin-files - safe action
	echo $SPIN > "${__locks_LOCKS_DIR}/$EFFECTIVE_DIRNAME/$$.spin"
	status=$?

	# Free the master lock
	rmdir "${__locks_LOCKS_DIR}/$EFFECTIVE_DIRNAME/.lock"
	
	# Return the return value of the spin-file creation command
	return $status
}

#
# dirTryLock <DirName>
#	Tries to set a lock on a directory. If lock is 
#	already set - returns immediately with error.
#
#	Parameters:
#	DirName - The name of the directory we wish to lock.
#	
#	The function exits with:
#		0 - The directory was successfully locked
#		1 - Lock was already set
#		2 - The lock object is not initialized
#
dirTryLock()
{
	local DIR_NAME=$1
	
	# Resolve effective directory name
	__locks_findEffectiveDirname "$DIR_NAME" || return ${__locks_ERR_COULD_NOT_RESOLVE_DIR}
	local EFFECTIVE_DIRNAME=$retval
	
	# Check if the directory-lock is initialized
	[[ -e "${__locks_LOCKS_DIR}/$EFFECTIVE_DIRNAME/$$.spin" ]] || return ${__locks_ERR_NO_SPIN_FILE}
	
	__locks_setMasterLock "${__locks_LOCKS_DIR}/$EFFECTIVE_DIRNAME"
	
	__locks_deadlockCleanup "$DIR_NAME"

	# Check if there is a lock on the directory
	if ls -d "${__locks_LOCKS_DIR}/$EFFECTIVE_DIRNAME"/.lock.* > /dev/null 2>&1 ; then
		# Remove the master-lock
		rmdir "${__locks_LOCKS_DIR}/$EFFECTIVE_DIRNAME/.lock"
		
		return ${__locks_ERR_DIR_IS_LOCKED}
	fi

	# Create a lock file for this proccess
	(umask 0 && touch "${__locks_LOCKS_DIR}/$EFFECTIVE_DIRNAME/.lock.$$")

	# Remove the master-lock
	rmdir "${__locks_LOCKS_DIR}/$EFFECTIVE_DIRNAME/.lock"
	
	# If we got here, everything worked just file.
	return 0
}

#
# dirLock <DirName>
#	Sets a lock on a directory.
#
#	Parameters:
#		DirName - The name of the directory we wish to lock.
#
#	The function exits with:
#		0 - The directory was successfully locked
#		2 - The lock object was not initialized
#
dirLock()
{
	local DIR_NAME=$1
	
	# Resolve effective directory name
	__locks_findEffectiveDirname "$DIR_NAME" || return ${__locks_ERR_COULD_NOT_RESOLVE_DIR}
	local EFFECTIVE_DIRNAME=$retval
	
	#  Loop trying to lock the directory
	while true ; do
		dirTryLock "$DIR_NAME"
		local status=$?

		# If the result of the TryLock is other than an error that says that the directory is locked, return it
		[[ $status != ${__locks_ERR_DIR_IS_LOCKED} ]] && return $status

		# The return value was the __locks_ERR_DIR_IS_LOCKED error. Sleep and try again.
		sleep $(cat "${__locks_LOCKS_DIR}/$EFFECTIVE_DIRNAME/$$.spin" 2> /dev/null) > /dev/null 2>&1 || sleep ${__locks_DEFAULT_SLEEP_TIME}
	done
}

#
# dirUnlock <DirName>
#	Free a directory from its lock.
#
#	Parameters:
#		DirName - The name of the directory we wish to unlock.
#
#	The function exits with:
#		0 - The directory was successfully unlocked
#		non-zero - Unlocking failed
#
dirUnlock()
{
	local DIR_NAME=$1
	
	# Resolve effective directory name
	__locks_findEffectiveDirname "$DIR_NAME" || return ${__locks_ERR_COULD_NOT_RESOLVE_DIR}
	local EFFECTIVE_DIRNAME=$retval
	
	# Check if the directory-lock is initialized
	[[ -e "${__locks_LOCKS_DIR}/$EFFECTIVE_DIRNAME/$$.spin" ]] || return ${__locks_ERR_NO_SPIN_FILE}
	
	__locks_setMasterLock "${__locks_LOCKS_DIR}/$EFFECTIVE_DIRNAME"

	__locks_deadlockCleanup "$DIR_NAME"

	# Remove my lock file
	rm -f "${__locks_LOCKS_DIR}/$EFFECTIVE_DIRNAME/.lock.$$" > /dev/null 2>&1

	# Remove the master lock
	rmdir "${__locks_LOCKS_DIR}/$EFFECTIVE_DIRNAME/.lock" > /dev/null 2>&1

	ls -la "${__locks_LOCKS_DIR}/$EFFECTIVE_DIRNAME/".lock.* > /dev/null 2>&1 && return ${__locks_ERR_DIR_IS_LOCKED}
	
	return 0
}

#
# dirDestroyLock  <DirName>
#	Destroys the lock object. After this action the process will no longer be able to use the lock object.
#	To use the object after this action is done, one must initialize the lock, using dirInitLock.
#
#	Parameters:
#		DirName - The name of the directory that we with to destroy its lock.
#
#	The function exits with:
#		0	The action finished successfully.
#		1	The action failed. The directory is locked by your own process. Unlock it first.
#		2	The action failed. Your process did not initialize the lock.
#		3	The directory path could not be resolved.
#
dirDestroyLock()
{
	local DIR_NAME=$1
	
	# Resolve effective directory name
	__locks_findEffectiveDirname "$DIR_NAME" || return ${__locks_ERR_COULD_NOT_RESOLVE_DIR}
	local EFFECTIVE_DIRNAME=$retval
	
	# Make sure that the directory is not locked
	dirTryLock "$DIR_NAME"
	if [[ "$?" == "${__locks_ERR_DIR_IS_LOCKED}" ]] ; then
		# Check if the directory is locked by this proccess
		if [[ -e "${__locks_LOCKS_DIR}/$EFFECTIVE_DIRNAME/.lock.$$" ]] ; then
			# We can't destroy our lock while it is locked!!!
			return ${__locks_ERR_DIR_IS_LOCKED}
		fi
		
		# The directory is locked by someone else. We remove our spin file,
		# and do not touch anything else.
		rm -f "${__locks_LOCKS_DIR}/$EFFECTIVE_DIRNAME/$$.spin"
		return 0
	fi
	dirUnlock "$DIR_NAME"

	__locks_setMasterLock "${__locks_LOCKS_DIR}/$EFFECTIVE_DIRNAME"

	# Remove my spoin file
	rm -f "${__locks_LOCKS_DIR}/$EFFECTIVE_DIRNAME/$$.spin"
	# Clean the locks directories tree of this lock, as possible
	# The first thing we clean is the master-lock.
	pushd "${__locks_LOCKS_DIR}/$EFFECTIVE_DIRNAME" > /dev/null
	local curr_subdir=".lock"
	while rmdir "$curr_subdir" 2>/dev/null ; do
		curr_subdir=$PWD
		[[ "$curr_subdir" == ${__locks_LOCKS_DIR} ]] && break

		cd ..

		__locks_spinCleanup "$PWD"
		__locks_deadlockCleanup "$PWD"

	done
	popd > /dev/null

	return 0
}

#
# spinCleanup <DirName>
#	Cleans all unneeded spinfiles from DirName.
#	This function removes spin-files. 
#	This function does not lock the directory, even when removing
#	the files (non-safe action). That is because it is an internal
#	function that is to be used only by this library.
#	When maintaining this file notice that this is a function that
#	does not protect you from doing nasty stuff.
#	
#	If this function will be used without locking first, it can
#	cause problems. This is an internal function, so nothing like
#	that should never happened. If it does, sorry, we do not supply
#	`Stupid user protection'.
#	
#	Parameters:
#		DirName - The name of the directory we wish to clean from spinfiles.
#
#	The function exits with:
#		0 - The directory was successfully unlocked
#		non-zero - Unlocking failed
#
__locks_spinCleanup()
{
	local DIR_NAME=$1
	
	# Resolve effective directory name
	__locks_findEffectiveDirname "$DIR_NAME" || return ${__locks_ERR_COULD_NOT_RESOLVE_DIR}
	local EFFECTIVE_DIRNAME=$retval
	
	# Clean dead processes spin files
	local spinfile
	for spinfile in $(ls "${__locks_LOCKS_DIR}/$EFFECTIVE_DIRNAME"/*.spin 2> /dev/null) ; do
		local pid=${spinfile%.spin}
		pid=${pid##*/}
		ps -ef | awk '{print $2}' | grep -q "^$pid$" || rm -f $spinfile
	done
}

#
# deadlockCleanup <DirName>
#	Cleans all locks that belong to dead processes.
#	This function removes lock-files. 
#	This function does not lock the directory, even when removing
#	the files (non-safe action). That is because it is an internal
#	function that is to be used only by this library.
#	When maintaining this file notice that this is a function that
#	does not protect you from doing nasty stuff.
#	
#	If this function will be used without locking first, it can
#	cause problems. This is an internal function, so nothing like
#	that should never happened. If it does, sorry, we do not supply
#	`Stupid user protection'.
#	
#	Parameters:
#		DirName - The name of the directory we wish to clean from deadlocks.
#
#	The function exits with:
#		0 - The directory was successfully unlocked
#		non-zero - Unlocking failed
#
__locks_deadlockCleanup()
{
	local DIR_NAME=$1
	
	# Resolve effective directory name
	__locks_findEffectiveDirname "$DIR_NAME" || return ${__locks_ERR_COULD_NOT_RESOLVE_DIR}
	local EFFECTIVE_DIRNAME=$retval
	
	# Clean dead proccesses spin files
	local lockfile
	for lockfile in $(ls "${__locks_LOCKS_DIR}/$EFFECTIVE_DIRNAME/".lock.* 2> /dev/null) ; do
		local pid=${lockfile##*/.lock.}
		if ! ps -ef | awk '{print $2}' | grep -q "^$pid$"  ; then
			rm -rf "$lockfile"
		fi
	done
}

# setMasterLock <DirFullPath>
#	Sets a master lock on a directory.
#	It tries to set it for 5 seconds.
#	If the master lock is set after those 5 seconds,
#	the function will sleep random amount of time (up to 1 second)
#	and will try again by calling itself recursively.
#
#	Notice that after calling this function the object will stay locked till
#	this lock is removed. This lock is not cleared by the deadlock cleanup
#	function. Therefore, if the master-lock not removed and the process exits
#	you can kiss your object good-bye. You will need to violently remove the lock.
#
#	There is no removeMasterLock function. To remove the lock you simply rmdir.
#	This lock is made to prevent two processes from setting process-specific lock
#	at the same time. Therefore, one should simply delete the directory once done
#	setting (or removing) process-specific lock.
#
#	Parameters:
#		DirFullPath - The full path of the object directory.
#
#	Return value:
#		This function returns only after setting the lock. If it returned the
#		directory was successfully locked.
#
__locks_setMasterLock()
{
	local DIR_FULL_PATH=$1

	local tries=0
	while [[ $tries -lt 50 ]] ; do
		# Creating the directory to lock
		mkdir -p "$DIR_FULL_PATH"
		# Try to set the master lock
		mkdir "$DIR_FULL_PATH/.lock" >/dev/null 2>&1 && return
		sleep 0.1
		let "tries++"
	done

	if [[ $tries -eq 50 ]] ; then
		rmdir "$DIR_FULL_PATH/.lock"
		sleep $(echo "" | awk '{srand(); print rand()}')
		__locks_setMasterLock "$DIR_FULL_PATH"
	fi
}