Accepting request 131512 from home:lrupp

The openSUSE admins make heavy use of this tool since years now. 
So I think it's time to include it officially in the next release of openSUSE and Base:System should be the devel project.

OBS-URL: https://build.opensuse.org/request/show/131512
OBS-URL: https://build.opensuse.org/package/show/Base:System/withlock?expand=0&rev=1
This commit is contained in:
Ismail Dönmez
2012-08-24 19:49:33 +00:00
committed by Git OBS Bridge
commit e17cacdc00
5 changed files with 318 additions and 0 deletions

23
.gitattributes vendored Normal file
View File

@@ -0,0 +1,23 @@
## Default LFS
*.7z filter=lfs diff=lfs merge=lfs -text
*.bsp filter=lfs diff=lfs merge=lfs -text
*.bz2 filter=lfs diff=lfs merge=lfs -text
*.gem filter=lfs diff=lfs merge=lfs -text
*.gz filter=lfs diff=lfs merge=lfs -text
*.jar filter=lfs diff=lfs merge=lfs -text
*.lz filter=lfs diff=lfs merge=lfs -text
*.lzma filter=lfs diff=lfs merge=lfs -text
*.obscpio filter=lfs diff=lfs merge=lfs -text
*.oxt filter=lfs diff=lfs merge=lfs -text
*.pdf filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text
*.rpm filter=lfs diff=lfs merge=lfs -text
*.tbz filter=lfs diff=lfs merge=lfs -text
*.tbz2 filter=lfs diff=lfs merge=lfs -text
*.tgz filter=lfs diff=lfs merge=lfs -text
*.ttf filter=lfs diff=lfs merge=lfs -text
*.txz filter=lfs diff=lfs merge=lfs -text
*.whl filter=lfs diff=lfs merge=lfs -text
*.xz filter=lfs diff=lfs merge=lfs -text
*.zip filter=lfs diff=lfs merge=lfs -text
*.zst filter=lfs diff=lfs merge=lfs -text

201
withlock Normal file
View File

@@ -0,0 +1,201 @@
#!/usr/bin/env python
# Copyright 2009,2010 Peter Poeml
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#
#
# withlock -- http://code.google.com/p/withlock/
#
#
# A locking wrapper that make sure that a program isn't run more than once.
# It creates locks that are valid only while the wrapper is running, and thus
# will never require a cleanup, e.g. after a reboot.
# Parts of the locking strategy, and parts of the usage semantics, of this
# script were inspired from with-lock-ex.c, which was written by Ian Jackson and
# placed in the public domain by him.
#
#
# Usage is simple. Instead of your command
# CMD ARGS...
# you simply use
# withlock LOCKFILE CMD ARGS...
#
# See --help output for more options.
__version__ = '0.2'
import os
import os.path
import errno
import sys
import time
import stat
import fcntl
import signal
import atexit
from optparse import OptionParser
class SignalInterrupt(Exception):
"""Exception raised on SIGTERM and SIGHUP."""
def catchterm(*args):
raise SignalInterrupt
for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
num = getattr(signal, name, None)
if num: signal.signal(num, catchterm)
def cleanup(lockfile):
try:
os.unlink(lockfile)
except:
pass
def main():
usage = 'usage: %prog [options] LOCKFILE CMD ARGS...'
version = '%prog ' + __version__
parser = OptionParser(usage=usage, version=version)
parser.disable_interspersed_args()
parser.add_option('-w', '--wait',
dest='wait',
help="wait for maximum SECONDS until the lock is acquired",
metavar="SECONDS")
parser.add_option("-q", "--quiet",
action="store_true", dest="quiet", default=False,
help="if lock can't be acquired immediately, silently "
"quit without error")
parser.add_option("-v", "--verbose",
action="store_true", dest="verbose", default=False,
help="print debug messages to stderr")
(options, args) = parser.parse_args()
usage = usage.replace('%prog', os.path.basename(sys.argv[0]))
if len(args) < 2:
sys.exit(usage)
lockfile = args[0]
cmd = args[1:]
waited = 0
if options.wait:
options.wait = int(options.wait)
if options.verbose:
sys.stderr.write('lockfile: %r\n' % lockfile)
sys.stderr.write('cmd: %r\n' % cmd)
# check that symlink attacks in the lockfile directory are not possible
lockdir = os.path.dirname(os.path.realpath(lockfile)) or os.curdir
lockdir_mode = stat.S_IMODE(os.stat(lockdir).st_mode)
if options.verbose:
sys.stderr.write('lockdir: %r\n' % lockdir)
sys.stderr.write('lockdir mode: %s\n' % oct(lockdir_mode))
if (lockdir_mode & stat.S_IWGRP) or (lockdir_mode & stat.S_IWOTH):
sys.stderr.write('withlock: the destination directory for %r is %r, \n'
' which is writable by other users. That allows for symlink attacks. \n'
' Choose another directory.\n' \
% (lockfile, lockdir))
sys.exit(3)
prev_umask = os.umask(0066)
lock = open(lockfile, 'w')
while 1 + 1 == 2:
try:
fcntl.lockf(lock, fcntl.LOCK_EX | fcntl.LOCK_NB)
break
except IOError, e:
if e.errno in [ errno.EAGAIN,
errno.EACCES,
errno.EWOULDBLOCK,
errno.EBUSY ]:
if options.wait:
if waited >= options.wait:
if options.quiet:
if options.verbose:
sys.stderr.write('quitting silently\n')
sys.exit(0)
else:
sys.stderr.write('could not acquire lock\n')
sys.exit(1)
if options.verbose and waited == 0:
sys.stderr.write('waiting up to %ss for lock\n' \
% options.wait)
time.sleep(1)
waited += 1
continue
elif options.quiet:
if options.verbose:
sys.stderr.write('quitting silently\n')
sys.exit(0)
else:
sys.exit('could not acquire lock')
try:
os.stat(lockfile)
break
except OSError, e:
if e.errno == errno.ENOENT:
sys.exit('====== could not stat %s, which we have just locked' \
% lockfile)
atexit.register(cleanup, lockfile)
os.umask(prev_umask)
import subprocess
rc = subprocess.call(' '.join(cmd), shell=True)
sys.stdout.flush()
sys.stderr.flush()
if options.verbose:
sys.stderr.write('command terminated with exit code %s\n' % rc)
if options.verbose:
sys.stderr.write('removing lockfile\n')
sys.exit(rc)
if __name__ == '__main__':
try:
main()
except SignalInterrupt:
print >>sys.stderr, 'killed!'
except KeyboardInterrupt:
print >>sys.stderr, 'interrupted!'

23
withlock-README.SuSE Normal file
View File

@@ -0,0 +1,23 @@
= About =
withlock is a locking wrapper script to make sure that some program isn't run
more than once. It is ideal to prevent periodic jobs spawned by cron from
stacking up.
The locks created are valid only while the wrapper is running, and thus will
never require a cleanup, as after a reboot. Thus, the wrapper is safe and easy
to use, and much better than implementing half-hearted locking within scripts.
= Usage =
Usage is simple. Instead of your command
CMD ARGS...
you simply use
withlock LOCKFILE CMD ARGS...
Run withlock --help to see more options.
Note: the lockfile LOCKFILE must not be placed in a publicly writable
directory, because that would allow a symlink attack. For that reason,
withlock disallows lockfiles in such locations.

14
withlock.changes Normal file
View File

@@ -0,0 +1,14 @@
-------------------------------------------------------------------
Thu Aug 23 18:21:16 UTC 2012 - lars@linux-schulserver.de
- updated to svn revision 5 which updates the year of Copyright,
fixes a typo and add an URL to project page to the comment header
- add project URL
- require python
- specfile cleanup
-------------------------------------------------------------------
Wed Nov 18 16:14:41 CET 2009 - lrupp@suse.de
- initial package, version 0.2

57
withlock.spec Normal file
View File

@@ -0,0 +1,57 @@
#
# spec file for package withlock
#
# Copyright (c) 2009-2012 SUSE LINUX Products GmbH, Nuernberg, Germany.
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
# upon. The license for this file, and modifications and additions to the
# file, is the same license as for the pristine package itself (unless the
# license for the pristine package is not an Open Source License, in which
# case the license is the MIT License). An "Open Source License" is a
# license that conforms to the Open Source Definition (Version 1.9)
# published by the Open Source Initiative.
# Please submit bugfixes or comments via http://bugs.opensuse.org/
#
Name: withlock
Version: 0.2
Release: 1
License: Apache License, Version 2.0
Summary: A locking wrapper script
Url: http://code.google.com/p/withlock/
Group: System/Management
Requires: python
Source0: %{name}
Source1: %name-README.SuSE
BuildRoot: %{_tmppath}/%{name}-%{version}-build
BuildArch: noarch
%description
withlock is a locking wrapper script to make sure that some program isn't run
more than once. It is ideal to prevent periodic jobs spawned by cron from
stacking up.
The locks created are valid only while the wrapper is running, and thus will
never require a cleanup, as after a reboot. Thus, the wrapper is safe and easy
to use, and much better than implementing half-hearted locking within scripts.
%prep
#
%build
#
%install
install -Dm755 %{SOURCE0} %{buildroot}%{_bindir}/%{name}
install -Dm644 %{SOURCE1} %{buildroot}%{_defaultdocdir}/%{name}/README.SuSE
sed -i "s|/usr/bin/env python|%{_bindir}/python|g" %{buildroot}%{_bindir}/%{name}
%clean
rm -rf %{buildroot}
%files
%defattr(-, root, root)
%doc %{_defaultdocdir}/%{name}
%{_bindir}/%{name}
%changelog