ADMIN-Tipp: Locks für die Shell

Jede Woche erscheint in unserem Newsletter ein neuer ADMIN-Tipp. Eine Sammlung aller Tipps finden Sie im Archiv der ADMIN-Tipps.

Jedes Shellskript, das auf ein gemeinsam benutztes File zugreift, sollte einen Locking-Mechanismus implementieren. Aber Vorsicht: Die einfachsten Ideen funktionieren schlecht.

Ein Lockfile soll ausschließen, dass verschiedene Prozesse oder mehrere Instanzen desselben Skripts gleichzeitig in ein bestimmtes File schreiben, denn das würde sehr wahrscheinlich Datenmüll produzieren. Das scheint nicht besonders schwer: Man wartet bis kein Sperrfile mehr existiert und legt danach ein eigenes an - fertig. Das könnte etwa so aussehen:

while [ -f $lockfile ] ; 
   do  sleep 1
done
touch $lockfile

Die Sache hat allerdings einen Haken: Wenn das Swapping den Prozess zufällig zu dem Zeitpunkt auslagert, an dem er das "done" verarbeitet, aber das "touch" noch nicht ausgeführt hat, dann existiert für einen konkurrierenden Prozess in der nächsten Zeitscheibe kein Lockfile. Dieser Prozess legt also ein eigenes an. Jetzt kommt der pausierte Prozess zurück und führt das "touch" aus. In der Folge glauben beide Prozesse, sie hätten exklusiv Zugriff auf die Ressource - in Wirklichkeit kommen sie sich aber ins Gehege.

Um eine solche Race Condition zu vermeiden haben die Autoren von Procmail ein nützliches kleines Tool geschaffen, das Bestandteil der meisten Linux-Distributionen ist. Es enthält das Shell-Kommando "lockfile", das Sperrdateien sicher erzeugen kann. Benutzt wird es prinzipiell so:

lockfile important.lock
...
<Zugriff auf das gesicherte File>
...
rm -f important.lock

Ein etwas ausführlicheres Beispiel sieht auszugsweise so aus:

...
if [ -z "$(which lockfile | grep -v '^no ')" ] ; then
  echo "$0 failed: 'lockfile' utility not  found in PATH." >&2  
  exit 1
fi

if [ "$action" = "lock" ] ; then  
  if ! lockfile -1 -r $retries "$1" 2> /dev/null;
    then echo "$0: Failed: Couldn't create lockfile in time" >&2
    exit 1
  fi
else    # action = unlock  
  if [ ! -f "$1" ] ; then
    echo "$0: Warning: lockfile $1 doesn't exist to unlock" >&2
    exit 1
  fi
  rm -f "$1"
fi

exit 0

Der Name des Lockfiles wurde dem Skript hier als erster Parameter übergeben ($1). Über die Variable $retries lässt sich die Anzahl Wiederholungen einstellen, nach deren Überschreitung das Skript kapituliert. Man kann mit -l (locktimeout) übrigens auch eine zeitliche Grenze für die maximale Lebensdauer eines Locks angeben.

05.03.2013

Ähnliche Artikel

comments powered by Disqus
Einmal pro Woche aktuelle News, kostenlose Artikel und nützliche ADMIN-Tipps.
Ich habe die Datenschutzerklärung gelesen und bin einverstanden.

Konfigurationsmanagement

Ich konfiguriere meine Server

  • von Hand
  • mit eigenen Skripts
  • mit Puppet
  • mit Ansible
  • mit Saltstack
  • mit Chef
  • mit CFengine
  • mit dem Nix-System
  • mit Containern
  • mit anderer Konfigurationsmanagement-Software

Ausgabe /2023