#!/usr/bin/env python # -*- coding: iso-8859-15 -*- """ Gestion de lock Copyright (C) Frédéric Pauget Licence : GPLv2 """ import os,string,time,sys, affich_tools from commands import getoutput from user_tests import getuser from fcntl import lockf, LOCK_EX, LOCK_NB, LOCK_UN import errno def wait_lock(lock_name, lock_comment='', d=None): """Attend la disponibilité d'un lock en utilisant le framework Twisted. Si d est de type Deferred, on est en mode asynchrone. """ from twisted.internet import reactor, defer try: make_lock(lock_name, lock_comment, nowait=1, quiet=True) # On a le lock if not d: # On est en mode synchrone return defer.succeed(None) # On appelle le callback car on est en mode asynchrone print "We got the lock, in asynchronous mode" d.callback(None) except AssertionError: # On a pas le lock if not d: # On est en mode synchrone, on va passer en asynchrone d = defer.Deferred() # On essaie de nouveau dans 200 ms. reactor.callLater(0.2, wait_lock, lock_name, lock_comment, d) return d def make_lock(lock_name, lock_comment='',nowait=0, quiet=False) : """ Création d'un lock si nowait=1 fait un sys.exit(254) quand un ancien lock actif est rencontré """ lock_dir = '/var/lock/gestion' try: os.mkdir(lock_dir) except OSError: pass lock_file = "%s/%s" % (lock_dir, lock_name) # On créé une zone d'exclusion lock_fd_dl=open("%s-dotlock" % lock_file, "w") # On demande un verrou exclusif try: lockf(lock_fd_dl, LOCK_EX | LOCK_NB) except IOError, e: if e.errno not in [errno.EACCES, errno.EAGAIN]: raise if nowait: if quiet: # On va plutot lever une exception raise AssertionError('In critical section') else: sys.stderr.write('\tpropriétaire : inconnu\n\tpid : inconnu\n\tdémarré depuis inconnu\n') sys.exit(254) else: # La procédure de lock est deja en cours d'execution, on essaie un peu plus tard time.sleep(0.5) return make_lock(lock_name, lock_comment) if os.path.isfile(lock_file) : ### Lock existant # Lecture du lock fd = open(lock_file, "r") pid= fd.readline().strip() user = fd.readline().strip() fd.close() # Informations sur le processus lockant if os.system( "ps ax | grep -q '^%s '" % pid ) : # Le script lockant ne tourne plus os.remove(lock_file) elif nowait : if not quiet: sys.stderr.write('Lock : %s\n' % lock_file) l=getoutput("ps -ax -o pid,etime | awk '($1 == %s)'" % pid) data = [ user , pid , l.strip() ] # Formatate de etime s = data[-1].split('-') if len(s)==2 : txt = '%s jour(s) ' % s[0] s=s[1] else : txt = '' s=s[0] s = s.split(':') if len(s) == 3 : txt = '%sh%smin%ss' % tuple(s) elif len(s) == 2 : txt = '%smin%ss' % tuple(s) else : txt = '???' data[-1]=txt if not quiet: sys.stderr.write('\tpropriétaire : %s\n\tpid : %s\n\tdémarré depuis %s\n' % tuple(data) ) sys.exit(254) else: # On va plutot lever une exception raise AssertionError(tuple(data)) else : # Il faut attendre a = affich_tools.anim('\tattente du lock') for i in range(8) : time.sleep(1) a.cycle() sys.stdout.write('\r') return make_lock(lock_name, lock_comment) ### Prise du lock lock_fd = file(lock_file,"w") try: utilisateur = getuser() except: utilisateur = "inconnu" lock_fd.write("%s\n%s\n%s" % (os.getpid(), utilisateur, lock_comment) ) lock_fd.close() # On enleve le verrou système lockf(lock_fd_dl, LOCK_UN) lock_fd_dl.close() def remove_lock( lock_name ) : """ Destruction du lock """ lock_dir = '/var/lock/gestion' lock_file = "%s/%s" % (lock_dir, lock_name) try : fd = open(lock_file, "r") if fd.readline().strip()=="%s" % os.getpid(): os.remove(lock_file) fd.close() except : pass