Bewertung: 2


Die Kandidaten sollten in der Lage sein, einen Kernel für verschiedene Anforderungen zu patchen, auch etwa um Kernel-Updates oder Bug-Fixes zu implementieren oder Unterstützung für neue Hardware einzubauen. Dieses Prüfungsziel beinhaltet auch, in der Lage zu sein, angewendete Patches eines existierenden Production-Kernels wieder zu entfernen.

Schlüsseldateien, Begriffe und Hilfsmittel beinhalten:

  • patch
  • Makefile
  • gzip
  • bzip

Patchen eines Kernels

Aufsteigende Upgrades eines Kernels werden als Patch veröffentlicht. Wenn Sie zum Beispiel eine Kernelversion 2.4.14 nutzen und einen Patch bemerken, der patch-2.4.15.gz heißt und für den 2.4er Kernel ausgezeichnet ist, dann kann Ihr Kernel damit zur Version 2.4.15 aktualisiert werden, indem dieser Patch angewendet wird.

Der Hintergedanke dieser Technik ist leicht zu verstehen. Ein kompletter Quellbaum des Linux-Kernels ist um die 70-80 MByte groß. Wenn für jede kleine Änderung der komplette Quellbaum aus dem Netz geladen werden sollte, so würde das einen erheblichen Aufwand bedeuten, obwohl sich vielleicht nur 100 Textzeilen im Quelltext zwischen den beiden Versionen unterscheiden. Ein Patch beinhaltet nur die Beschreibung der Unterschiede zwischen den verschiedenen Versionen und ist damit wesentlich kleiner.

Das Programm patch ist jetzt in der Lage, solche Patches einzuspielen und die entsprechenden Neuerungen im bestehenden Quelltext vorzunehmen. Bleiben wir einmal bei dem oben genannten Beispiel und spielen den Vorgang durch.

In aller Regel werden Patches mit Kompressionsprogrammen komprimiert, um die Ladezeit zu verringern. Zur Anwendung kommen dabei sowohl das klassische gzip, als auch das modernere bzip, das wesentlich bessere Kompressionsraten hat. Welche Version jeweils benutzt wurde, lässt sich anhand der Endung der Patchdatei ermitteln:

EndungBedeutung
keineNicht komprimiert
.gzMit gzip komprimiert
.bzMit bzip komprimiert
.bz2Mit bzip2 komprimiert

Die entsprechenden Programme werden weiter unten auf dieser Seite noch genauer beschrieben.

Unser Patch heisst patch-2.4.15.gz, ist also mit gzip komprimiert. Das Programm patch(1) ist nicht in der Lage, selbst zu entpacken, wir müssen also entweder den Patch vor der Anwendung dekomprimieren, oder ihn in einer Pipe dekomprimiert an patch(1) weiterleiten.

Es empfielt sich allerdings, vor dem Patchen eine Sicherheitskopie der aktuellen Kerneldateien zu erstellen. Dazu werden mit make clean zunächst einmal alle Objektdateien (.o) gelöscht und anschließend mit tar ein entsprechendes Backup Archiv erstellt:

  cd /usr/src/linux
  make clean
  cd ..
  tar -czvf kernelbackup.tgz linux    

Jetzt haben wir – falls etwas schiefgehen sollte – ein komplettes Backup in der Datei kernelbackup.tgz.

Damit das Programm patch(1) überhaupt weiß, in welchen Verzeichnis es arbeiten soll, muß ihm der Pfadlevel mitgegeben werden. Wir haben hier zwei Möglichkeiten. Entweder wechseln wir ins Verzeichnis /usr/src und rufen das Programm mit

  zcat  patch-2.4.15.gz | patch -p0 

auf oder wir wechseln direkt in das Verzeichnis /usr/src/linux_x.xx.xx (wobei hier natürlich die xx durch die Versionsnummern ersetzt werden müssen) und schreiben

  zcat  patch-2.4.15.gz | patch -p1 

Mit der Option -p0 oder -p1 wird also der Pfadlevel angegeben. In beiden Fällen muß aber natürlich die entsprechende Patchdatei (hier patch-2.4.15.gz) im jeweilig verwendeten Verzeichnis liegen.

In beiden Fällen wird patch(1) eine ziemliche Menge Ausgaben produzieren, die gelinde gesagt schwer zu verstehen sind. Um diese Ausgaben auf Fehlermeldungen zu reduzieren, kann dem Programm patch(1)-s (silent) mitgegeben werden.

Neuere Versionen von patch(1) legen nicht mehr automatisch Backups der veränderten Dateien an. Um auch mit diesen neueren Versionen noch Backup-Dateien zu bekommen, sollte dem Programm patch(1) die Option -b oder –backup mitgegeben werden. Die Dateiendungen der Backup-Dateien heißt .orig

Dateien, bei denen der Patch nicht funktioniert haben sollte, werden in der Form Dateiname.rej (rej für reject – abgelehnt) abgespeichert. Diese .rej Dateien können wiederum als Patches eingesetzt werden, nachdem sie von Hand angepasst wurden.

Jeder Patch beeinflusst nur die Quelldateien des Kernels! Damit die Änderungen tatsächlich wirksam werden, muß natürlich der Kernel erneut compiliert werden (siehe Kernel compilieren) und zwar am besten vollständig mit vorherigem Löschen der Objektdateien und Ermitteln der Abhängigkeiten:

  make clean
  make dep
  make bzImage
  make modules
  make modules_install

Nur so wird tatsächlich sichergestellt, dass keine Reste der alten Version übrigbleiben.

Einen angewendeten Patch wieder rückgängig machen

Wenn sich herausstellen sollte, dass ein eingespielter Patch wieder rückgängig gemacht werden soll, etwa weil er nicht richtig funktioniert oder gar die Compilation zu Fehlermeldungen führt, so gibt es zwei Möglichkeiten:

Entweder haben wir – vorausdenkend wie oben beschrieben – eine Backup-Datei angelegt, die wir jetzt einfach auspacken, oder wir wenden den Patch sozusagen umgekehrt wieder an. Das geschieht erneut mit dem Programm patch(1) und dem gerade aufgespielten Patch, nur diesmal mit der Kommandozeilenoption -R. Also in unserem Beispiel mit

  zcat patch-2.4.15.gz | patch -p0 -R 

Das Programm patch(1) nimmt jetzt alle Veränderungen zurück, wir sollten jetzt also wiederum die ursprüngliche Form der Quelldateien vorfinden.

Komprimierte oder unkomprimierte Patches

Das Programm patch(1) erwartet seine Eingaben von der Standard-Eingabe (stdin). Wenn eine Patch-Datei also unkomprimiert vorliegt (also weder die Endung .gz, noch .bz hat), dann kann patch einfach wie folgt aufgerufen werden:

  patch [Optionen] < Patchdatei

Wenn allerdings die Patchdatei komprimiert sein sollte, dann müssen wir sie vorher entpacken, damit patch(1) sie verstehen kann. Die beiden oben beschriebenen Kompressionsformen gzip oder bzip sollen hier noch kurz erläutert werden.

Mit gzip komprimierte Patches

Das Programm gzip(1) komprimiert bestehende Dateien, wobei die Orginaldatei durch eine komprimierte Datei mit selben Namen, aber der zusätzlichen Endung .gz ersetzt wird. Eine solche Datei kann auf zweierlei Weise wieder entkomprimiert werden.

Eine mit gzip(1) komprimierte Datei kann mit gunzip(1) einfach wieder entkomprimiert werden. Dabei wird die komprimierte Datei durch die entkomprimierte Datei ersetzt, die dann wiederum den alten Namen (ohne die .gz Endung) trägt. In diesem Fall würde also bei einem Patch zunächst die komprimierte Patchdatei entkomprimiert und anschließend das Programm patch(1) auf die unkomprimierte Datei angewandt:

  gunzip patch-2.4.15.gz
  patch -p0 < patch-2.4.15

Die zweite Methode arbeitet mit dem Programm zcat(1), das eine bestehende, mit gzip(1) komprimierte Datei nur entpackt auf die Standard-Ausgabe ausgibt. Die Datei selbst wird dabei nicht verändert, nur die Ausgabe ist entkomprimiert. Um einen Patch anzuwenden können wir also wie oben schreiben

  zcat patch-2.4.15.gz | patch -p0

In diesem Fall verbleibt die Patch-Datei komprimiert auf dem Dateisystem, nur ihr entpackter Inhalt wird an patch(1) weitergeleitet.

Beide Programme, gunzip(1) und zcat(1) sind übrigens nur symbolische Links auf gzip(1).

Mit bzip oder bzip2 komprimierte Patches

Die modernere Kompressionsform wird mit dem Programm bzip oder bzip2 erreicht. Viele Patches sind heute auch schon mit dieser Methode komprimiert. Es gilt das für gzip gesagte, nur dass die beiden Programme zum Entpacken der komprimierten Dateien hier jetzt bunzip(1), bunzip2(1) und bzcat(1) heißen. Ansonsten funktionieren sie genau equivalent zu den unter gzip genannten Methoden.