System-nahe Programmierung mit Python

von Hubert Schmid vom 2013-01-27

Python ist hauptsächlich bekannt als moderne und dynamische Programmiersprache mit sinnvollen Abstraktionen, um die Entwicklung guter und verständlicher Quelltexte zu unterstützen. Die umfangreiche Standardbibliothek enthält allerdings auch zahlreiche Funktionen, die eine sehr genaue Systemsteuerung ermöglichen – insbesondere unter Linux. Im folgenden Text zeige ich ein paar Beispiele zu dem Modul os aus Python 3.3, die mit höheren Programmiersprachen kaum zu erreichen sind.

Dateisystem-Struktur

Für die meisten Programmiersprachen gibt es Bibliotheken, um auf hierarchische Dateisysteme zuzugreifen. Dabei erfolgt in fast allen Fällen der Zugriff auf ein Verzeichnis oder eine Datei über einen sogenannten Pfad, der entweder relativ zum Arbeitsverzeichnis oder absolut angegeben wird. Dieses Vorgehen ist jedoch anfällig für sogenannte Race-Conditions: Pfadsegmente können zwischen Operationen gezielt oder zufällig manipuliert werden, wodurch die folgenden Operationen des Programms auf falschen Annahmen beruhen.

Um diese Race-Conditions zu vermeiden, können in Python 3.3 fast alle Verzeichnis- und Dateioperationen relativ zu einem zuvor geöffneten Verzeichnis erfolgen. Dabei werden die offenen Verzeichnisse über sogenannte Deskriptoren referenziert. Das folgende Programm beispielsweise zeigt, wie man damit sicher über das tmp-Verzeichnis iterieren kann – ohne anfällig für Link-Manipulationen zu sein.

def usage(fd): used = 0 st = os.stat(fd) if stat.S_ISDIR(st.st_mode): for filename in os.listdir(fd): flags = os.O_RDONLY | os.O_NOFOLLOW child = os.open(filename, flags, dir_fd=fd) try: used += usage(child) finally: os.close(child) elif stat.S_ISREG(st.st_mode): used += st.st_size return used print(usage(os.open('/tmp', os.O_RDONLY)))

Datei-Meta-Information

Python unterstützt neben den üblichen Meta-Informationen für Berechtigungen und Eigentümer, die mit os.stat bestimmt und mit os.chmod und os.chown geändert werden können, auch die sogenannten Extended Attributes. Sie können Benutzer-definierte Key-Value-Paare aufnehmen und werden seit Jahren von fast allen Dateisystemen unter Linux unterstützt. Eingesetzt werden sie hingegen kaum. Dennoch gibt es viele Szenarien für eigene Anwendungen, für die sie prädestiniert sind.

for pathname in sys.argv[1:]: if pathname.endswith('.txt'): os.setxattr(pathname, 'user.mime_type', 'text/plain')

Datei-Inhalt

Mit Python kann man Dateien lesen und schreiben, wie man das aus anderen Programmiersprachen kennt. Darüber hinaus enthält Python 3.3 aber auch Funktionen, die man nicht so häufig sieht. So werden beispielsweise Operationen auf großen Dateien relativ gut unterstützt.

fd = os.open(pathname, os.O_RDONLY) try: os.posix_fadvise(fd, 0, 0, os.POSIX_FADV_SEQUENTIAL) offset = 0 data = os.read(fd, 16384) while data: # process data data = os.read(fd, 16384) finally: os.close(fd)

Mit os.posix_fadvise kann die Anwendung dem Betriebssystem signalisieren, dass die Datei im Wesentlichen sequentiell verarbeitet wird. Das Betriebssystem verwendet üblicherweise die Information, um teure I/O-Operationen besser zu planen und damit die Gesamtperformance signifikant zu verbessern.

Genauso kann die Anwendung beim Schreiben dem Betriebssystem mit os.posix_fallocate mitteilen, wie viele Daten erwartet werden, so dass das Betriebssystem die Dateiblöcke möglichst zusammenhängend auf der Festplatte allokieren kann. Abschließend werden mit os.truncate die überschüssigen Blöcke wieder abgeschnitten.

Fazit

Aus meiner Sicht ist Python wesentlich mehr als nur eine weitere Skriptsprache. Einerseits löse ich damit viele meiner Bash-Skripte ab, da sich Python bei vergleichbarem Entwicklungsaufwand wesentlich robuster verhält und besser mit der wachsenden Komplexität der Skripte skaliert. Andererseits entwickle mittlerweile auch viele kleinere Anwendungen mit Python, da die Performance meistens hinreichend gut und die Sprache bestens geeignet ist. Daher gehe ich davon aus, dass Python sich insbesondere im Bereich der Systemadministration in den nächsten Jahren noch stärker gegen die Alternativen durchsetzt.