Druckversion | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Während der Installation eines Linuxsystems erfolgte eine mehr oder minder detaillierte Selektion zu installierender Software. Der Bedarf der nachträglichen (De)Installation verschiedener Pakete wird irgendwann erwachsen, sei es, um die zu klein gewordene Festplatte von unnötigem Ballast zu befreien oder ein Programm durch eine verbesserte Nachfolgeversion zu ersetzen. Vielleicht lag das gute Stück Software gar nicht »meiner« Distribution bei? Dann muss es nachträglich ins System eingespielt werden. I.A. ist es nicht erforderlich, jede Version seiner favorisierten Distribution zu erwerben. Solange diese nicht an ihrer Basis schrauben (bspw. eine neue Version der glibc verwenden), schont die alleinige Aktualisierung der häufig verwendeten Programme nicht nur den Geldbeutel, sondern schließt auch den möglichen Ärger aus, den eine Neuinstallation (bzw. Update) so mit sich bringt. »Never change a running system« lautet die Maxime des Profis! Programme unter Unix bestehen nur in seltenen Fällen aus einer einzelnen Datei. Zum Paket zählen zumeist noch Dokumentationen, Bibliotheken, Konfigurationsdateien u.v.m. Als Struktur eines solchen Pakets haben sich im wesentlichen drei Formate etabliert:
Bei rpm und deb handelt es sich im Unterschied zu tar-Archiven um Paket-Manager, d.h., diese Formate kombinieren die reine Archivierung zusammen gehöriger Paketkomponenten mit Methoden zur sauberen (De)Installation und Aktualisierung. Sie helfen ungemein, die Konsistenz der installierten Software zu wahren. Kompilierte Versionen zu aktualisierter Software bieten die Großen der Branche meist wenige Tage nach deren Freigabe auf ihren Servern ein. Das Herunterladen und Installieren solcher Pakete im »richtigen« Format mit den distributionseigenen Werkzeugen birgt selten Probleme in sich und sollte stets bevorzugt werden. Nicht jede Distribution jedoch misst einem Programm die gleiche Aufmerksamkeit zu. Teils existieren vorkompilierte Pakete nur in einem Format, das ausgerechnet »meine« Distribution nicht unterstützt! In einem solchen Fall kann ein kleines Perl-Skript namens alien Wunder wirken, konvertiert es so manches Paket doch anstandslos in ein Fremdformat. Wer aus dem vollen Fundus des reichhaltigen Angebots an freier Software schöpfen will, der wird vielfach den Tar-Archiven (*.tar, *.tar.gz, *.tgz) begegnen. Der Vorteil des Formats liegt in seiner Unabhängigkeit von jeglicher Dateisystemstruktur. Der gravierende Nachteil gründet sich auf die zumeist fehlende Routine zur sauberen (De)Installation solcher Programme. Das Tar-Archiv ist auch die bevorzugte Verpackung für Quellcode-Pakete. Hieraus ein lauffähiges Programm zu kompilieren, kann spielend leicht als auch frustrierend bis unmöglich sein. Der Neuling auf dem Gebiet der Programmierung wird einem Fehler hilflos gegenüber stehen. Die Prinzipien, nach denen sich eine Ursache des Fehlers eingrenzen lässt, möchten wir daher erläutern.
Open Source lebt von der Mitarbeit Freiwilliger. Natürlich ist in erster Linie der Programmierer gefragt, aber die Beihilfe eines jeden in der Testphase garantiert das Aufspüren möglichst vieler Fehler (»Irgend jemand entdeckt den Fehler. Ein anderer wird ihn beheben können.«). Aus diesem Grund gehen die meisten Projekte bereits in einer sehr frühen Entwicklungsphase an die Öffentlichkeit und bieten Schnappschüsse des aktuellsten Standes auf ihren Servern an. Eine als Beta-Version gekennzeichnete Software muss nicht zwingend fehlerbehaftet sein. Oftmals fehlen noch wesentliche Teile, die die Entwickler für notwendig erachten, der eine oder andere Anwender aber nicht benötigt. Warum sollte man das Programm nicht doch schon nutzen? Derartige Entwicklerversionen werden nahezu ausschließlich als Quelltext angeboten. Was tut man nun, nachdem das Paket auf die lokale Platte geladen wurde? Das verbreitete Format für Quellcodepakete ist das Tar- Archiv (Tape Archiver). Typische Endungen solcher Dateien lauten ».tar« bzw. im Fall komprimierter Daten ».tar.gz« oder ».tgz«. In neuerer Zeit finden Sie vermehrt ».tar.bz2«, was auf eine Komprimierung mit dem effektiven Burrows-Wheeler-Algorithmus hindeutet. Auch in den Source-Rpm-Paketen (».src.rpm«), in welcher Form vielfach die Quellen fertiger Projekte verbreitet werden, stecken letztlich Tar-Archive, mit denen analog zur folgenden Beschreibung zu verfahren ist. Beginnend mit dem Entpacken des Quellpakets betrachten wir die notwendigen Schritte zu einem lauffähigen Programm anhand von Galeon, einem auf Mozilla basierenden Browser-Projekt. Im Januar 2001 war die Version 09pre3 aktuell. Entpacken der Quellen
Eine Reihe der enthaltenen Dateien sind typisch für Quellcodepakete (nahezu jedes aktuelle Projekt verwendet autoconf/automake, womit die Existenz bestimmter Dateien zwingend gegeben ist). INSTALL sollten Sie auf jeden Fall lesen, beinhaltet die Datei doch eine detaillierte Beschreibung der notwendigen Schritte bis zur Installation der kompilierten Programme. README beschreibt zumeist die Fähigkeiten des Programms und seine Anwendung. In NEWS erfahren Sie die wesentlichen Änderungen der Version gegenüber seinen Vorgängern und TODO gibt einen Ausblick auf die zukünftige Richtung. Falls Probleme bei den weiteren Schritten auftauchen, sollten Sie einen Blick in FAQ (»Häufig gestellte Fragen«) werfen, bevor Sie sich Hilfe suchend an die Projektmitglieder wenden. Erzeugen des MakefilesBefindet sich im Stammverzeichnis des Quellpakets keine Datei mit dem Namen »Makefile« (bzw. »makefile«), so muss diese zunächst erstellt werden. Hierfür existieren (fast) immer Shellskripte namens configure (manchmal auch kurz config oder config.sh). Starten Sie dieses:
Sinn solcher configure-Skripte ist das Erzeugen eines auf die lokalen Gegebenheiten zugeschnittenen Makefiles. Was konkret passiert, hängt natürlich vom Verfasser des Skripts ab (i.d.R. greift der Verfasser hierzu auf vorgefertigte Makros des autoconf/automake-Pakets zurück). Typische Punkte sind:
Unser Beispiel deckt eine der häufigsten Ursachen für einen gescheiterten »configure«-Aufruf auf: Das Fehlen eines Pakets (hier Mozilla der Version 0.7). Abhilfe sollte die nachträgliche Installation des erforderlichen Pakets bringen. Nicht selten jedoch stottert »configure« über fehlende Dateien, die aber definitiv installiert sind. »configure« selbst sucht allerdings nur in Standardpfaden; wird es dort nicht fündig, ist die Fehlermeldung die Konsequenz. Spätestens hier sollten Sie die Option --help konsultieren. Eventuell findet sich eine Option, mit der »configure« der rechte Fleck gewiesen werden kann.
Dem (Shell-)Programmierer bleibt als letzte Option noch die direkte Suche des Kodeabschnitts, der den Fehler verursachte. Ein hartes Setzen der dortigen Variablen kann über so manche Klippe helfen, erfordert jedoch tiefe Kenntnisse der Programmierung. Wenn »configure« mit der Systemumgebung zufrieden ist, wird es abschließend ein Makefile erzeugen:
ÜbersetzenBei dem im vorigen Schritt erzeugten Makefile handelt es sich um eine Steuerdatei, die die weiteren Schritte zur Kompilierung automatisiert. I.d.R. beinhaltet sie eine Reihe so genannter »Ziele« (targets). Jedes dieser Targets führt zu einem anderen Kontrollfluss. Detailliertere Informationen finden Sie im Kapitel Unix-Werkzeuge. Das erste im Makefile formulierte Ziel ist das Default-Target, d.h. wird make ohne den Namen eines Ziels aufgerufen, beginnt es mit der Ausführung dieses ersten Targets. Die Übersetzung des Paketes beginnt somit i.A. durch den Aufruf von make:
Die zahlreichen Ausgaben während des »Builds« protokollieren die Tätigkeit von make. Schritte des Kompilierens finden (bei C- und C++-Programmen) in den mit »gcc ...« bzw. »g++...« beginnenden Zeilen statt. Interessant sind die Ausgaben wohl eher für den Programmierer. Bewahren Sie die Ruhe, wenn »Warnings« über den Bildschirm rauschen. Die Compiler weisen hier auf mögliche Fallstricke des Programms hin, die (zumeist;-) vom Programmierer beabsichtigt sind. Ein Abbruch des Vorgangs mit einer »Error«-Meldung ist hingegen ein schwerwiegender Fehler. Bei der Fülle der Ursachen würde eine detaillierte Diskussion dieser einen einführenden Programmierkurs bedingen, aber zu einigen Fehlerklassen lassen sich prinzipielle Ansatzpunkte zur Fehlereingrenzung angeben: Datei oder Verzeichnis nicht gefunden
Eine typische Ausgabe für eine fehlende Datei oder eine Datei, die nicht gefunden werden kann (»gnomesupport.h« im Beispiel). Hier sollen Sie zunächst feststellen, ob die Datei im System existiert: »locate Dateiname«. Falls nicht, so durchsuchen Sie die Installations-CDs bzw. im Web nach dem Paket, das diese Datei enthält, und installieren es nach. Ist die Datei allerdings vorhanden, so bieten sich im Falle einer Header-Datei (Endung ».h«) drei Lösungswege an: Setzen der Compiler-UmgebungsvariablenDie Variable »C_INCLUDE_PATH« (im Falle des C-Compilers [gcc, cc, egcs]) bzw. »CPLUS_INCLUDE_PATH« (C++-Compiler [g++, c++]) wird mit dem Pfad zur fehlenden Datei belegt:
Anpassen des MakefilesIm Makefile kann nach dem den Fehler verursachenden Compileraufruf gesucht werden. Am Ende der Zeile ist -IPfad_zur_Datei hinzuzufügen (diese Möglichkeit bleibt wohl eher dem Profi vorbehalten). Link in ein Standard-Include-VerzeichnisEs kann ein Link auf die vermisste Datei in einem der Standard-Include-Verzeichnisse (bspw. »/usr/include«) gesetzt werden. Bei dieser »unsauberen« Methode empfiehlt es sich, den Link nach erfolgreicher Kompilierung des Pakets wieder zu entfernen.
Eine Bibliothek wurde nicht gefunden
Der Linker kann eine Bibliothek nicht lokalisieren. »-lgnome« ist eine Compileranweisung, die Bibliothek »libgnome.a« hinzuzulinken (Beachten Sie die Namensgebung: Als Compileroption wird vom Dateinamen der Bibliothek sowohl das Prefix »lib« als auch das Suffix ».a« weggelassen!). Falls die alleinige Installation des die Bibliothek enthaltenden Pakets das Problem nicht beheben kann, sollte die Variable »LIBRARY_PATH« gesetzt und exportiert werden (mehrere Pfade lassen sich durch Doppelpunkt getrennt angeben):
Undefined Reference...
Derartige Meldungen können so ziemlich alles bedeuten. Für 90% der Fälle zeichnet eine falsche Bibliotheksversion dafür verantwortlich; eine Aktualisierung kann notwendig werden. Wer über etwas Programmiererfahrung verfügt, könnte vorerst das Kommando nm bemühen und die Bibliothek suchen, die das fehlende Symbol (im Beispiel »g_free«) definiert. Existiert sie, so kann die Compilerzeile im Makefile um die Anweisung des Linkens dieser Bibliothek ergänzt werden. Weitere Hinweise zur Problematik von Bibliotheken und Symbolen finden Sie unter Bibliotheken und im Abschnitt zur Bashprogrammierung (Komplexe Anwendungen). Sie merken schon, dass die Behandlung von Compiler-Fehlern besser dem Experten vorbehalten sein sollte. Mit Ausnahme der nicht gefundenen Bibliothek erfordert eine saubere Lösung stets den Eingriff in die Quellen des Pakets (zumindest des Makefiles). Ich möchte es bei diesem kleinen Ausflug in die Trickkiste der Programmierer belassen... InstallationDie genaue Anweisung kann der Datei INSTALL aus dem Quellverzeichnis entnommen werden. Der Ort der Installation lässt sich häufig beim einführenden »configure« per Option variieren, der Vorgang selbst wird üblicherweise im Makefile realisiert:
Weniger verbreitet ist die Beigabe eines Skripts install oder install.sh. Falls vorhanden, finden Sie dieses im Basisverzeichnis des Pakets oder unterhalb des dortigen ./bin-Verzeichnisses. DeinstallationNur wenige Projekte bringen eine eigene Routine zum Entfernen der ins System eingespielten Dateien mit. Denn fast ebenso wie die Dokumentation scheut der Entwickler derartige Nebensächlichkeiten, sodass automatische »Hilfsroutinen« - falls überhaupt - erst bei Abschluss eines Projekts zu diesem hinzugefügt werden. Für den Fall, dass eine Deinstallation per Skript vorgesehen ist, finden Sie im Basisverzeichnis des Quellpakets ein Skript uninstall bzw. uninstall.sh, in manch anderen Fällen beinhaltet das Makefile ein »Ziel« zur Deinstallation:
So sehr der Anwender die Möglichkeit der automatischen Deinstallation auch missen mag; die Entwickler haben teils bewusst auf deren Implementierung verzichtet. Die Problematik steckt in der fehlenden Datenbasis, die die Zugehörigkeiten und Abhängigkeiten der einzelnen Dateien protokolliert. Stellen Sie sich vor, was passiert, wenn Sie Bibliotheken deinstallieren, die von einer Reihe anderer Anwendungen gefordert werden. Diese Anwendungen würden nicht mehr funktionieren! Wünschenswert wäre, wenn per Makefile aus den kompilierten Quellen ein Rpm-oder Deb-Paket erzeugt werden würde. Dass dies mit relativ vertretbarem Aufwand möglich ist, soll in späteren Abschnitten demonstriert werden. Vielleicht inspiriert dies den Leser, die Installation solcher »handerzeugten« Pakete über den Bau eines eigenen RPM-Pakets zu realisieren...
Wenn Entwickler eines Projekts es für sinnvoll erachten, eine neue Version des Quellkodes zu veröffentlichen, so ist der Weg des geringsten Aufwands das Schnüren eines aktualisierten Komplettpakets. Bei geringem Datenaufkommen ist das Verfahren durchaus legitim, aber bei mehrere Megabytes umfassenden Quellkode-Dateien wird so mancher freiwillige Tester das langwierige und kostspielige Herunterladen der letzten Version scheuen. Effizient wäre, ein Paket nur einmalig komplett zu übertragen und nachfolgend einzig die Änderungen zwischen den Versionen einzupflegen. Ein solches Verfahren wird als Patchen (»korrigieren«) bezeichnet und die Datei, die die Unterschiede zwischen zwei Versionen beinhaltet, nennt sich Patch. Erstellen eines PatchesNichts schult das Verständnis für die Funktionsweise eines Programms eindrucksvoller als ein Beispiel. Deshalb soll dem »Patchen« eine kurze Abhandlung über das Erstellen der benötigten Patchdateien voran stehen. Sicher wird nur der Programmierer in die Verlegenheit gelangen, Patches zu erstellen. Deswegen werden wir uns auf das minimal erforderliche Wissen beschränken. Ausgangspunkt sei eine einfache Textdatei:
Aufgrund der immensen Wichtigkeit der Aussagen des Inhalts der Datei kopieren sie sich eine Menge Leute. Der Autor indess modifiziert den Text in einer seiner kreativen Phasen:
Allen Eignern der Kopie der ersten Version die neue Datei zukommen zu lassen ist bei solch kleinen »Projekten« praktikabel. Aber ebenso genügt es, die Änderungen kund zu geben. Und hierbei gelangt das Kommando diff zum Einsatz:
Zugegeben... das Beispiel ist schlecht gewählt, da die Ausgabe von »diff« den Umfang der »neuen« Datei bereits überschreitet. Aber bekanntlich heiligt der Zweck die Mittel. Die Ausgabe von diff bedarf einer Aufbereitung, um patch die notwendigen Informationen zukommen zu lassen. Im Beispiel wählten wir das unified Ausgabeformat (Option -u), das eine »leserliche« Form des context Formats (Option -c) darstellt. Genau diesen »Kontext« benötigt später patch, um die Änderungen an den richtigen Positionen der Zieldatei einpflegen zu können. Mit den vorgestellten Optionen werden neben den Unterschieden auch die ersten drei unveränderten Zeilen in die Ausgabe von diff übernommen. Sie dienen als »Anhaltspunkt« für patch, um auch dann noch »sinngemäß korrekte« Korrekturen zu ermöglichen, wenn Zeilen in das Original eingefügt oder daraus entfernt wurden. Genügt der Kontext nicht, um eine eindeutige Abbildung zu erzielen, kann er mittels -U n (unified) bzw. -C n auf n Zeilen gesetzt werden. Nun bestehen große Projekte nicht nur aus einer Datei. Und für jede einen eigenen Patch zu erstellen, würde das Interesse am Patchen schnell schwinden lassen. Aus diesem Grund kann diff auch auf Verzeichnisse angesetzt werden. Ist nur eine der beiden Angaben in der Kommandozeile ein Verzeichnis, so wird der Name der anderen Datei in diesem Verzeichnis gesucht. Ist diff fündig, vergleicht es diese beiden Dateien. Handelt es sich bei beiden Argumenten um Verzeichnisse, vergleicht diff alle Dateien mit identischen Namen und erzeugt eine gemeinsame Ausgabe. Dateien, die nur in einem Verzeichnis vorhanden sind, erscheinen als »Only in Verzeichnis: Datei« in der Ausgabe. Hier kann die Option --new-file hilfreich sein, um »neue« Dateien (die aus dem zweiten Verzeichnis) vollständig in die Ausgabe einfließen zu lassen (diff arbeitet so, als wäre die Datei vorhanden aber leer). Schließlich werden mit der Option -r auch Unterverzeichnisse rekursiv betrachtet. Um endlich zum Erstellen des notwendigen Patches zu gelangen... leiten wir die Ausgabe von diff in eine Datei:
Bei umfangreichen Patchdateien lohnt sich das Komprimieren derselben.
Einspielen eines PatchesDie Aktualisierung der Originaldatei anhand des Patches gestaltet sich für unser Beispiel äußerst einfach. Die Datei mit dem Patch ist zu entpacken und dem Programm patch über die Standardeingabe zuzuführen:
Wichtig ist, dass der Kommandoaufruf aus dem Verzeichnis mit der Originaldatei heraus erfolgt. Sonst würde patch die zu »patchende« Datei nicht finden. Patchdateien, die rekursiv über Verzeichnisse erzeugt wurden, enthalten anstatt des reinen Dateinamens den kompletten Pfad zu jeder zu »patchenden« Datei. Stimmen nun die Verzeichnisstrukturen beim Patch-Erzeuger und Patch-Anwender nicht überein, so wird »patch« die zu korrigierende Datei nicht finden und reagiert leicht verärgert:
Die erste Option, die Ihnen bleibt, wäre nun tatsächlich, den Zugriffspfad zur betreffenden Datei an der Eingabeaufforderung anzugeben. Bei wenigen Dateien ein legitimes Vorgehen; bei umfangreichen Patches artet die Methode nur zu schnell in echte Arbeit aus. Die Alternative, die lokale Verzeichnisstruktur dem des Patch-Erzeugers anzugleichen, ist ein gangbarer, aber ebenso unbequemer Weg. Besser, wir bemühen die Option -pAnzahl, die »patch« veranlasst, die angegebene Anzahl von Verzeichnisebenen aus den Pfadangaben in der Patchdatei zu entfernen. Aus einer Angabe von -p1 in obigem Beispiel resultiert, dass sowohl die Dateinamen »fibel_old/access.htm« als auch »linuxfibel/access.htm« als »access.htm« angenommen werden. Befinden Sie sich also im »Wurzelverzeichnis« des zu patchenden Zweigs, ist »patch« nun in der Lage, alle Dateien zu finden. Patchen ist genau das, was dieser Abschnitt vermuten lässt: Es ist schwierig und fehleranfällig. Aus diesem Grund sollte eine Sicherung der originalen Daten zum allgemeinen Vorgehen zählen; es genügt die Option -b (Backup), um die Arbeit von »patch« persönlich erledigen zu lassen. Für jede Datei, die nachfolgend verändert wird, wird zuvor eine Kopie als »Dateiname.orig« erzeugt (Suffix per Option änderbar). Im Fehlerfall - und bei etwas Kenntnis der Shellprogrammierung - richtet ein kleiner Einzeiler den Schaden:
Nicht jeder Fehler ist so schwerwiegend, als dass der ganze Patch gleich über den Haufen geworfen werden müsste. Manchmal betrifft es nur einzelne Dateien, die das Kommando nicht korrekt zu behandeln weiß. Gerade wer gern mit neuesten Kernelpatches experimentiert, wird einmal Patches einspielen, die sich mit den Änderungen eines früher angewandten Patches nicht vertragen. Kann »patch« Korrekturen nur zum Teil eindeutig in eine Datei einarbeiten, so legt es alle Bestandteile des Patches, mit denen es nichts anzufangen weiß, in eine Datei »Dateiname.rej« ab. Eventuell kann dieser »Rest« manuell an die richtigen Positionen geschrieben werden... Linuxfibel-PatchExemplarisch soll das Erzeugen und Einspielen eines Patches anhand der Linuxfibel demonstriert werden. Hierbei liegen die alten Quellen im Verzeichnis »fibel_old « und die neue Version befindet sich unterhalb von »linuxfibel«. Für »diff« verwenden wir die Optionen -u zum Erzeugen eines Kontexts, -r zum rekursiven Absteigen in die Unterverzeichnisse und --new-file zur Übernahme neuer Dateien in den Patch. Da es sich bei der Ausgabe von »diff« um Text handelt, lohnt sich das anschließende Komprimieren enorm:
Für das Einspielen des Patches nehmen wir nachfolgend an, dass sich die Dateien unterhalb von »/usr/share/doc/linuxfibel« und der Patch im Heimatverzeichnis von »user« befinden. Der folgende Aufruf aktualisiert die Dateien:
Seit dem Durchbruch der Paketformate Rpm und Deb hat die Bereitstellung kompilierter Software in Form von Tape Archiven stark abgenommen; die Gründe sind u.a. in der Einleitung zum Abschnitt des RedHat Package Managers zu lesen. Von den namhaften Distributionen ist Slackware als einzige diesem historischen Format treu geblieben. Sollten Sie in die Zwangslage geraten, ein solches Paket in ihrem (Nicht-Slackware-) System zu installieren, dann vergewissern Sie sich auf jeden Fall, dass die Verzeichnisstruktur im Paket auch relative Pfadangaben verwendet:
Nutzt das Paket absolute Pfadangaben (mit dem Backslash beginnend), so verwenden Sie sicherheitshalber die Option -C /Installationspfad, um die Dateien des Pakets nicht gleich ohne vorherigen Test direkt im Dateisystem zu verstreuen. Gerade hier handeln Sie sich eine Menge Probleme ein, wenn das Paket nicht auf die Verzeichnisstruktur Ihrer Distribution abgestimmt wurde. Nach der Installation (Option -x anstatt -t bei tar verwenden) sollten Sie zunächst das Programm in Augenschein nehmen, ob es Ihren Ansprüchen gerecht wird. Ist es erst einmal im Dateisystem installiert, ist das Entfernen aller zum Paket gehörigen Dateien doch vielfach recht aufwändig. Pakete mit enthaltenen relativen Pfadangaben beinhalten häufig ein Skript zur Installation desselben, typische Namen lauten »install« oder »install.sh«. Trotz solcher Installationshilfen bleibt das Entfernen schwierig, da jegliche Protokollierung zur Installation ausblieb. Sicherer ist die Konvertierung des Paketformats nach *.rpm oder *.deb mit Hilfe des Kommandos alien und anschließender Verwendung eines »richtigen« Paketverwaltungswerkzeugs. Bei Slackware - und ebenso in älteren Versionen nahezu aller weiteren Distributionen - finden Sie noch die Programme installpkg und removepkg, die - der Name spricht für sich - die Installation/Deinstallation vereinfachen. Beide Werkzeuge vermerken die Paketzugehörigkeit in Listen, sodass zumindest das saubere Entfernen eines Pakets gewährleistet ist. Und dennoch fehlt diesen Programmen die Mächtigkeit eines modernen Paketmanagers, um auch Abhängigkeiten zwischen verschiedenen Paketen auflösen zu können. Ebenfalls in die Werkzeuggruppe zur Verwaltung von "tgz"-Paketen gehörend, ist pkgtool, das letztlich nur eine augenfällige Verpackung für installpkg und removepkg ist: Abbildung 1: pgktool von Slackware Nicht zuletzt Sicherheitslücken, die diesen Programmen anhaften, führten zu ihrem heutigen Schattendasein...
Management von SoftwarepaketenSowohl bei Quellkode als auch bei fertig kompilierten Programmen, die in Form von Tape Archiven verbreitet werden, entpuppt sich die Verträglichkeit mit bereits installierten Komponenten als Quelle häufigen Ärgers. Quellkodepakete schwächen das Problem ab, indem zumeist ein beiliegendes Skript zwingend abzuarbeiten ist (»configure«), sodass die Kompilierung und Installation erst gelingt, wenn gewisse Bedingungen erfüllt sind. Bei Binärpaketen offenbart sich die Lauffähigkeit meist erst nach der Installation. Hat ein solches Paket seine Dateien erst einmal in den Verzeichnissen des Systems verstreut, gleicht dessen saubere Entfernung oft einem Hürdenlauf... Den ersten Ansatz, durch eine Verwaltung der Dateilisten an zentraler Stelle den Problemen zu entgegnen, präsentierte »Slackware« mit dem schon genannten »pkgtool«. Bei Bezug auf die Pakete einer einzigen Distribution und einer einzigen Version (der von Slackware) war die saubere (De)Installation zwar gegeben, jedoch fehlten Mechanismen zur Versionsverwaltung, die erst ein Update - und damit eine der wesentlichen Anforderungen an eine Paketverwaltung - ermöglichten. Erst »RedHat« schuf mit dem RedHat Package Manager rpm eine ausgefeilte Lösung. Rpm selbst ist ein Programm, das mannigfaltige Aufgaben wahr nimmt, u.a.:
VersionsabfrageSämtliche Abfragen werden durch die Option -q (query) eingeleitet:
Abfragen können sich auf Einträge aus der RPM-Datenbank oder auf RPM-Pakete beziehen oder, anders ausgedrückt, auf installierte bzw. nicht installierte Pakete. Wichtig ist die Angabe der Quelle, insofern sich die Abfrage nicht auf ein installiertes Paket bezieht! Eine Auskunft über alle in der Datenbank erfassten RPM-Pakete samt ihren Versionsnummern veranlasst die Option -a:
Eine solche Anfrage ist bei der Suche nach einem installierten Paket sinnvoll, falls der genaue Name des Pakets unbekannt ist. Häufiger interessiert man sich für die Version einer installierten Komponente. Hierzu ist der »Query-Option« -q der Paketname nach zu stellen. Im Falle des gezielten Bezugs auf eine konkrete Version (wenn mehrere parallel installiert sind) kann der Name um Versions- und/oder Revisionsnummer ergänzt werden. Zulässige Anfragen bez. des Pakets »cpio« sind bspw:
Bezieht sich eine Anfrage auf eine RPM-Datei, so ist neben deren Namen die Option -p zu verwenden:
Beachten Sie, dass sich der Name einer Rpm-Datei nicht zwingend mit dem Namen des Pakets decken muss! Detailliertere AuskunftMit der reinen Versionsabfrage sind die Möglichkeiten noch lange nicht erschöpft. Aus Anwendersicht sind zunächst die Zugehörigkeiten von Dateien zu Paketen von Interesse. So setzt bspw. die Suche nach der Dokumentation zu einem Paket günstiger Weise bei einem Blick auf die Dateiliste an:
Die Option -l zeigt alle zu einem Paket gehörigen Dateien mit vollständigem Pfad an; -d beschränkt die Ausgabe auf die zugehörigen Dokumentationsdateien. Obiges Vorgehen bedingt allerdings die Kenntnis des Paketnamens, zu dem eine Datei gehört. Auch für diese Anfrage sieht rpm eine Option vor (-f), wobei die komplette Pfadangabe zur Datei erforderlich ist:
Der Vollständigkeit halber soll an dieser Stelle die Abfrage einer »SPEC«-Datei Erwähnung finden. Diese enthalten letztlich die Informationen zum Erzeugen eines Rpm-Pakets (ihr Aufbau wird uns im Rahmen des Paketbaus beschäftigen). Eine Anfrage liefert den Namen des Pakets, das durch diese SPEC-Datei erstellt werden würde:
Tiefer in den Gründen des Pakets forscht die Option -i, die neben den bereits genannten Informationen Weiteres zum Inhalt offenbart:
Um den Status der zu einem Paket gehörigen Dateien zu erfahren, bedienen Sie sich der Option -s:
Die Angaben entsprechen der Information in der Datenbank und decken sich nicht zwangsläufig mit den Gegebenheiten im Dateisystem. So besagt »normal«, dass - aus Sicht der Datenbank - die Datei so vorhanden ist, wie sie mit dem Paket installiert wurde. Ein »not installed« wird sichtbar, wenn ein Paket nur teilweise installiert wurde (gewisse »exclude«-Optionen); »replaced« erscheint bei Dateien, die durch eine Version aus einem Fremdpaket ersetzt wurden. Abfrage von AbhängigkeitenEs macht i.A. selten Sinn, Programme zu installieren, während von diesen benötigte Bibliotheken, Programme oder Interpreter fehlen. Sie würden ja doch nicht laufen. Das Rpm-Paket beinhaltet daher die Informationen, welche Pakete in welcher Version zuvor installiert sein müssen. Rpm wertet u.a. während der Installation und Deinstallation die Bedingungen für ein Paket intern aus, sodass sich die manuelle Abfrage oft erübrigt. In manchen Situationen finden sich allerdings Abhängigkeiten, die sich nicht automatisch auflösen lassen, bspw. wenn Paket A Fähigkeiten eines Pakets B benötigt, Paket B bedingt aber die vorherige Installation von Paket A. Natürlich vermag man solche Pakete auch unter Missachtung der Abhängigkeiten installieren. Günstig ist dennoch, durch vorherige Abfrage sicher zu stellen, dass im Nachhinein eine konsistente Installation vorliegt.
Wenn ein Paket bestimmte Anforderungen stellt, so sollte auch ein Paket existieren, das sie erfüllt. Der logische Schritt zur Verifizierung, ob sich ein Paket zur Installation eignet, ist somit der Test, ob die notwendige Software auf dem System existiert. Bei einer sauber geführten locatedb sollte auch ein Aufruf von »locate <Datei>« die Lösung offenbaren. Sicher ist jedoch die Anfrage an die Rpm-Datenbank:
Umgangssprachlich ließe sich letztere Abfrage als »Welches Paket bietet diese Fähigkeit?« interpretieren. Die Frage nach »Welche Fähigkeiten bietet dieses Paket an?«, würde eine --provide-Anfrage beantworten:
Und letztlich ist auch die Fragestellung »Welche Pakete benötigen diese Fähigkeit?« legitim, bspw. um festzustellen, ob ein Paket gefahrlos gelöscht werden kann:
Natürlich beschränken sich die Abhängigkeiten nicht allein auf den Paketnamen, sondern sie berücksichtigen ebenso Versionen, denn neuere Software bedingt zumeist auch neuere Bibliotheken... Alles in Ordnung?Wer die durch eine Distribution vorgegebenen Pfade zur Administration verlässt, der wird hier und da durch manuelle Eingriffe ins System nicht zuletzt die Belange der Rpm-Paketverwaltung berühren. Einfachstes Beispiel hierfür ist die Aktualisierung eines Pakets, das wiederum nur als Quellkode vorlag und somit unter Umgehung von rpm ins System gelangte. Oder aber bewusst »gelockerte« Rechte, um minder-privilegierten Benutzern das Ausführen mancher Programme zu ermöglichen. »Das Genie beherrscht das Chaos«. Doch da die Wenigsten aus unserer Mitte den Status eines Genies genießen und Dokumentation »per Voreinstellung« stiefmütterlich vernachlässigt wird, wird der Überblick über all die Änderungen bald verloren gehen. Kein Problem... bis zum Auftreten eines Problems. Dann ist es an der Suche, welche Änderung das Übel verbockt haben könnte. Damit derartige Integritätstests möglich werden, enthalten Rpm-Pakete mehrere Informationen. Eine Anfrage mit der Option --dump ist zwar eher zum internen Gebrauch von rpm gedacht, schult aber den Sinn für die nachfolgend vorgestellten Tests:
Von links nach rechts bedeuten die einzelnen Felder:
Aus Sicht des Administrators sind einzig die Änderungen relevant, die sich zwischen den Informationen in der Datenbank und der tatsächlichen Installation ergeben und hierfür bietet sich die Option -V an. Alle Dateien zu einem angegebenen Paket (bzw. zu allen installierten Paketen bei Kombination mit -a) werden einer Reihe von Tests unterzogen, wobei nur Dateien in der Ausgabe erscheinen, die mindestens einen der Tests nicht bestanden haben.
Der Punkt steht hierbei für einen bestandenen Test, die Buchstaben - bzw. die eine Ziffer - kodiert den Grund für ein Scheitern:
Konfigurationsdateien sind zusätzlich durch ein c vor dem Dateinamen gekennzeichnet, sodass schnell entschieden werden kann, ob eine Abweichung von den Informationen aus der Datenbank gewollt ist. Vermisste Dateien enthalten anstatt der Testdaten ein »missing«. Rpm-Dateien, die aus unbekannter Quelle stammen, sollten im Zweifelsfall auf ihre Unversehrheit hin untersucht werden. Ein checksig stellt durch Überprüfung der MD5-Prüfsumme die Originalität eines Pakets sicher:
Reparatur installierter Pakete»Wo gearbeitet wird, fallen auch Späne.«, erklärt ein bekanntes Sprichwort. Und wer hin und wieder am System manipuliert, wird auch Verluste verzeichnen. Irgend wann geht irgend etwas mit Gewissheit schief. Wenn dann gar nichts mehr geht, beginnt man besser von vorn, also mit der Neuinstallation der »verbastelten« Pakete. Eine der Installationsoptionen (siehe nachfolgenden Abschnitt) in Verbindung mit --replacepkgs erweisen sich als schlagkräftiges Argument:
Für den verbreiteten Fall, dass ein sorgloser Umgang mit den Dateirechten die Integrität des Systems in Frage stellt, lassen sich auch diese auf den »Originalzustand« zurück versetzen. Verwenden Sie hierzu die Option --setperms, um die Rechte eines Pakets zu restaurieren:
Um Eigentümer und Gruppenzugehörigkeit wieder herzustellen, ist --setugids die rechte Option. Quasi den »Supergau« bedeutet eine beschädigte RPM-Datenbank. Da sich nahezu die gesamte Abfragefunktionalität von rpm auf diese bezieht, ist ohne Datenbasis die gesamte Verwaltung nutzlos. rpm ist daher selbst in der Lage, eine bestehende Datenbank neu zu befüllen bzw. eine neue zu erzeugen:
In beiden Fällen kann per --dbpath ein zu /var/lib/rpm abweichende Pfad zur Datenbank angegeben werden. Installation von RPM-Paketen
Die Installation eines Pakets umfasst dessen Erstinstallation als auch die Aktualisierung bereits existierender Pakete. In letzterem Fall wird das alte Paket zuvor implizit aus dem System entfernt. Die Optionen zum Installieren sind -i und zur Aktualisierung -U (update). Da letztere Option im Falle, dass das Paket noch gar nicht installiert ist, wie -i arbeitet, sollte ihr Einsatz bevorzugt werden. Bei der erstmaligen Installation ist die Wirkung beider Aufrufe identisch:
Existiert das Paket hingegen bereits, scheitert -i:
Bez. der Aktualisierung von Paketen besteht jedoch oft der Wunsch, einzig bereits installierte Pakete zu ersetzen, ohne dieses ggf. zu installieren. In einem solchen Fall muss die Option -F (freshen) anstatt -U verwendet werden. Werkzeuge, die die Paketverwaltung in grafische Masken oder Skripte packen, präsentieren den Installationsvorgang häufig durch einen fort schreitenden Balken. Rpm trägt dafür selbst Sorge, wenn eine der Installationsoptionen (-i|-U|-F) mit -h (hash) kombiniert wird. Der Zusatz von -v schreibt den Paketnamen vor den Balken:
Ohne eine Installation zu vollziehen, arbeitet die Option --test. Sie kann zur Kontrolle heran gezogen werden, um von vorn herein Konflikte auszuschließen. Mitunter erweist sich erst in der Praxis, ob eine neuere Version einer Software das hält, was man sich von ihr verspricht. Dass sie mitunter mehr schadet als nutzt, ist leider nur allzu oft zu verzeichnen. Der Wunsch, auf die alte Version zurückzustellen, wird erwachsen. Es sollte einleuchten, dass -U oder -F eine »Aktualisierung« auf eine ältere Version abweisen und der Weg über eine vorherige Deinstallation ist dann doch unnötig weit. Einfacher ist der Verwendung der Option --oldpackage:
Im Zusammenhang mit der Abfrage von Paketabhängigkeiten wurde die Problematik wechselseitiger Bedingungen von Paketen bereits erörtert. Es findet sich mitunter keine Installationsreihenfolge bei mehreren voneinander abhängigen Paketen, sodass obige Mechanismen jeden Versuch einer Installation oder Aktualisierung abweisen. Per --nodeps lässt sich die Überprüfung durch rpm deaktivieren. Eine weitere explizite Aufforderung an rpm wird nötig, wenn ein Paket Dateien eines anderen Pakets entfernt, dessen Dateien in der RPM-Datenbank erfasst sind. --replacefiles zwingt rpm dieselben durch die »neue« Version zu ersetzen. Die »brutalste« Option, die --replacefiles, --replacepkg und --oldpackage in sich vereint, ist --force. Kombinieren Sie diese gar mit --nodeps, verdammen Sie rpm zum unbedingten Gehorsam... RPM-Pakete speichern neben den eigentlichen Dateien auch den Installationspfad, unter dem diese ins System zu spielen sind. Nicht zuletzt diese Festlegung erschwert zuweilen die Portierung eines für Distribution A erzeugten Rpm-Pakets auf die Distribution B, da diese womöglich eine abweichende Verzeichnisstruktur bevorzugt. Zumindest Pakete mit rein distributionsunabhängigen Inhalten (bspw. Dokumentationen) bedingen aber keinerlei Annahmen ob des eigentlichen Installationsorts, sodass deren Installationspfad (oft) als »änderbar« (engl.: relocatable) vermerkt ist. »Relocatable« Pakete lassen sich sowohl mit --prefix <Pfad> unterhalb eines Verzeichnisses installieren, wobei der komplette Installationspfad dann in diesem erscheint, als auch per --relocate <Alter_Pfad>=<Neuer_Pfad> komplett überschreiben. Um beim Beispiel des Linuxfibel-Basispakets zu bleiben, könnte ein alternativer Installationspfad wie folgt versucht werden:
Der Versuch scheitert leider, da das Paket nicht als »relocatable« gekennzeichnet wurde. Aber auch hierfür existiert eine Lösung in Form der Option --badreloc, die den Pfadwechsel erzwingt:
Entfernen von RPM-PaketenZum Entfernen von Paketen dient die Option -e:
Das Beispiel verdeutlicht, dass rpm auch hierbei die Abhängigkeiten zu weiteren installierten Paketen berücksichtigt. Die Deinstallation glückt erst, wenn kein anderes Paket mehr das zu entfernende bedingt. Natürlich kann hier ebenso mit --nodeps nachgeholfen werden, was allerdings zu unbrauchbaren Paketen führen kann. Ist ein Paket gleichzeitig in mehreren Versionen installiert, entfernt -e in Kombination mit --allmatches alle Vorkommen; einen sehr ausführlichen Report zu den einzelnen Abhängigkeiten bringen die Optionen -e --test --vv zum Vorschein.
VoraussetzungenDie meisten Rpm-Pakete beinhalten Programme nebst zugehöriger Bibliotheken, Dokumentationen, Konfigurationsdateien usw. Beim Erzeuger eines Pakets handelt es sich i.A. auch um den Entwickler des jeweiligen Programms, deshalb werden Rpm-Pakete zumeist direkt aus den Quellen gebaut, d.h. die zu verpackenden Dateien werden erst zum Zeitpunkt des Paketbaus erzeugt. Somit ergibt sich als erste Anforderung, die zum Erstellen eines Pakets erfüllt sein muss, dass die Quellen auf dem System korrekt kompilieren müssen (für das nachfolgend diskutierte Beispiel der Linuxfibel erübrigt sich diese Forderung, da sie keine Kompilierung bedingt). Die Arbeitsweise des Kommandos rpm wird durch eine oder mehrerer Konfigurationsdateien gesteuert. Beim Start durchsucht Rpm die Dateien »/usr/lib/rpmrc«, »/etc/rpmrc« und »~/.rpmrc« in benannter Reihenfolge und setzt alle Optionen anhand der zuletzt vorgefundenen Definition. Da die Datei »~/.rpmrc« aus dem Heimatverzeichnis eines Benutzers stets zuletzt gelesen wird, lassen sich selbst nutzerspezifische Anpassungen vornehmen. Aber vermutlich werden Sie nie in Verlegenheit gelangen, die Voreinstellungen korrigieren zu müssen... Existiert keine der obigen Dateien (auch nicht in anderen Verzeichnissen), so könnte es an einer unvollständigen Installation liegen. Zumindest in neueren RedHat-basierten Distributionen ist die Funktionalität zum Bau oft in ein »rpm-devel-Paket« ausgelagert. Schon eher Ziel eines Eingriffs dürfte die Forderung nach der Existenz einer Reihe von Verzeichnissen sein, die u.a. als Ablage für die Quellen, für die Bauanleitungen und für die fertigen RPM-Pakete dienen. Bspw. finden Sie in einem SuSE-System (ab 7.0) die folgenden Verzeichnisse vor: /usr/src/packages/BUILD In diesem Verzeichnis werden die Dateien vor dem Paketbau erzeugt
/usr/src/packages/RPMS Enthält die fertigen RPM-Pakete
/usr/src/packages/SOURCES Enthält die Quellen und Patches
/usr/src/packages/SPECS Enthält die SPEC-Dateien zu jedem Paket (quasi die Anleitung, wie ein Paket zu erzeugen ist).
/usr/src/packages/SRPMS Enthält die fertigen SRPM-Pakete (Quellen)
Um Pakete in der vordefinierten Umgebung zu erzeugen, sind Rootrechte erforderlich, was natürlich auf etlichen Entwicklersystemen aus Sicherheitsgründen nicht erwünscht ist. Einem Benutzer steht es deshalb frei, die vom Kommando rpm verwendete Struktur anzupassen, indem er die zu ändernden Makros in einer Datei »~/.rpmmacros« definiert. Die Syntax orientiert sich an der aus der »globalen« Makro-Datei »/usr/lib/rpm/macros«:
Wie im Auszug der Datei unschwer zu erkennen ist, würde das Überschreiben der Variablen »_topdir« genügen, um den Paketbau in einem alternativen Verzeichnisbaum zu vollziehen (diese Verzeichnisse müssten Sie natürlich noch anlegen):
Um auf Ihrem System die Makros mit den Verzeichnisdefinitionen in Erfahrung zu bringen, müssen Sie nicht erst die Konfigurationsdateien durchforsten. Bemühen Sie die Option »--showrc« von Rpm und suchen in der Ausgabe nach den Variablen »_rpmdir«, »_sourcedir«, »_specdir« und »_srcrpmdir«.
Für die nachfolgende Ausführung gehen wir von oben skizzierter Verzeichnisstruktur eines SuSE-Linux aus. Der BauplanDie entscheidende Datei für den Paketbau ist die so genannte SPEC-Datei, die allgemeine Informationen und eine Art Bauanleitung zum Paket beinhaltet. Die Datei selbst besteht aus mehreren Sektionen: Die PräambelDie Präambel enthält allgemeine Informationen zum RPM-Paket und zum Bau. Jeder Eintrag besitzt die Form:
wobei folgende Namen (»Tags«) möglich sind: Buildroot
(Alternatives) Verzeichnis, indem das Paket gebildet wird. Wird auf die Angabe verzichtet, so
werden die Dateien an ihren endgültigen Positionen im Dateisystem erzeugt. Zumindest für
Software im Teststadium ist dieses Verhalten denkbar ungeeignet. Bei gesetztem »Buildroot«
wird die benötigte Verzeichnisstruktur unterhalb des angegebenem Verzeichnisses erzeugt
(bezogen auf das Paket der Linuxfibel würde während des Paketbaus bspw. ein Verzeichnis
»/tmp/usr/share/doc/linuxfibel« angelegt werden, falls »Buildroot« auf
»/tmp« stünde).
Copyright Copyright-Informationen zur enthaltenen Software.
Conflicts
Namen von Paketen, die sich mit diesem RPM-Paket nicht vertragen. Die Installation wird bei einem
Konflikt abgelehnt, kann aber dennoch mittels --nodeps erzwungen werden.
Distribution Linuxdistribution, für die das Paket erzeugt wurde.
Group
Art der enthaltenen Software (mögliche Einträge werden von RedHat empfohlen und
liegen in einer ASCII-Datei »GROUPS«der Dokumentation zu Rpm bei)
Name Name des RPM-Pakets
Packager Name des Erzeugers des Pakets
Patch
Name einer Patchdatei, die zum Bau des Pakets erforderlich ist; mehrere Patches
können mittels mehrerer Patch-Einträge angegeben werden.
Prefix »Empfohlener« Installationspfad für ein verschiebbares Paket
Provides
Ein virtueller Paketname, der eine Einordnung in eine Anwendungsgruppe ermöglichen
soll. Somit kann der Anwender in manchen Installationsprogrammen aus einer Reihe von
Programmen auswählen, die nahezu dasselbe tun (bspw. bieten sowohl »sendmail«
als auch »qmail« einen »mail-server«).
Release
Versionsnummer des Pakets; "0" wenn es erstmals gepackt wird, "1" beim zweiten Mal.... D.h.
Versionsnummern sollten erhöht werden, wenn das Paket neu erzeugt wird ohne das sich
die Version der enthaltenen Software geändert hat.
Requires
Paketnamen und Versionen, die auf dem System vorhanden sein müssen (Paketabhängigkeiten).
Hier können ebenso die Namen virtueller Paketgruppen stehen, falls kein konkretes Programm
bedingt wird. Bez. Versionsnummern sind auch relative Angaben erlaubt: requires perl >=
5.0.
Source Name des enthaltenen Quell-Archivs; mehrere Archive lassen sich mittels mehrerer Source-Tags angeben
Summary Kurze Beschreibung zum Inhalt des Pakets
Url URL mit weiterführenden Informationen zum Paket.
Vendor Anbieter der Software
Version Versionsnummer der enthaltenen Software
Der entsprechende Abschnitt aus der SPEC-Datei zum Linuxfibel-RPM-Paket sieht wie folgt aus:
Die %description-SektionEine aussagekräftige Beschreibung zum Inhalt des Pakets ermöglicht die Sektion »description«. Der Text kann auf beliebig viele Zeilen ausgedehnt werden.
Die %prep-SektionHier findet die Vorbereitung zum Bau des Pakets statt. Letztlich beinhaltet die Sektion verschiedene Shellbefehle, die die Quellen für den anschließenden Kompiliervorgang - sofern ein solcher erforderlich ist - aufbereiten. Ein gebräuchlicher erster Schritt ist das Entfernen der »Reste« früherer Paketbau-Vorgänge. Dann werden i.d.R. die Quelldateien ins BUILD-Verzeichnis entpackt. Ggf. kann in einem weiteren Schritt das Einspielen von Patches erfolgen.
Die %build-SektionIm Falle von Quellpaketen muss die zu installierende Software erst erzeugt werden. Genügt hierfür ein einfacher Aufruf von make, kann die build-Sektion entfallen. Im anderen Fall werden die auszuführenden Schritte angegeben. %changelogBeinhaltet Informationen über die wesentlichen Änderungen der enthaltenen Software. %cleanRPM entsorgt die »Überreste« der Installation stets selbst, mit der Ausnahme der Verwendung eines buildroot-Verzeichnisses. Ein solches sollte im clean-Eintrag entfernt werden.
Die %files-SektionHier folgen die Dateien, die das RPM-Paket enthalten soll. Jede Datei steht auf einer eigenen Zeile und jeder Dateiname ist mit einem Zeilenumbruch abzuschließen. Alternativ lassen sich die von den Shells bekannten Wildcards verwenden. Innerhalb der files-Sektion können einzelne Dateien mit weiteren Tags versehen werden: %attr Für die anzugebende Datei werden bestimmte Attribute gesetzt:
Anstelle des Wertes kann ein Minus verwendet werden (-, root, root), um den aktuellen Wert beizubehalten. %config[(missingok|noreplace)]
Die Datei wird als Konfigurationsdatei gekennzeichnet; die optionalen Tags geben
an, ob eine Datei [bspw. beim Entfernen des Pakets] fehlen darf (missingok) oder ob
das Ersetzen einer existierenden Datei zu verhindern ist (noreplace).
%defattr
Die angegebenen Attribute gelten für alle Dateien aus der files-Sektion (Angabe wie bei »attr«)
%dir
Das angegebene Verzeichnis wird ins Paket integriert, nicht aber die enthaltenen Dateien und Unterverzeichnisse
(ohne die Angabe wird bei Verzeichnissen auch deren Inhalt zum Paket addiert)
%doc
Die Datei wird als Dokumentation ausgewiesen, womit die Installation per Rpm-Option »--excludedocs«
verhindert werden kann.
%docdir
Dateien aus dem angegebenen Verzeichnis werden ins Paket integriert und als
Dokumente gekennzeichnet. Datei aus /usr/[share/]doc, /usr/[share/]info und
/usr/[share/]man müssen nicht explizit als Dokumentationen ausgewiesen
werden.
%ghost
Die Datei selbst ist nicht im Paket enthalten, sie wird aber bei der Installation
als leere Datei erzeugt.
%license Die angegebene Datei enthält Lizenzinformationen
%readme Die angegebene Datei enthält lesenswerte Informationen
%verify Die angegebenen Attribute einer Datei werden bei einer Überprüfung berücksichtigt
Die Liste der einzufügenden Dateien kann auch [teilweise] in einer separaten Datei stehen. Diese wird wie folgt eingebunden:
Die %install-Sektion%post, %postunDie Sektionen beinhalten Bashskripte oder die Namen der dem RPM-Paket beiliegenden Skriptdateien, die nach der Installation (%post) bzw. nach dem Löschen (%postun) des Pakets ausgeführt werden sollen.
%pre, %preunDie Sektionen beinhalten Bashskripte oder die Namen von dem RPM-Paket beiliegenden Skriptdateien, die vor der Installation (%pre) bzw. vor dem Löschen (%preun) des Pakets ausgeführt werden sollen.
Anmerkung: Die im Beispiel verwendeten Befehle erzeugen bzw. entfernen die Dateien zur Druckversion der Linuxfibel. Das Skript print_version.sh wird ausführlich im Abschnitt Shells, Bash-Programmierung, Komplexe Anwendungen behandelt. Der eigentliche BauErzeugt wird ein RPM-Paket mit Hilfe des Kommandos rpm selbst:
Die mit Stadium bezeichneten Optionen steuern den Umfang des Paketbaus:
Im Zusammenhang mit c oder i können führende Schritte übersprungen werden, indem mit der Option --short-circuit die Startphase des Baus spezifiziert wird. Sinnvoll ist diese Option beim Aufspüren von Fehlern, indem diese nicht an den Orginaldateien des Pakets gefixt werden, sondern die Suche in der Kopie des BUILD-Verzeichnisses erfolgt. Nun sollte natürlich die %prep-Sektion zum folgenden Testlauf nicht erneut ausgeführt werden, da sonst die originalen Quellen den Inhalt des BUILD-Verzeichnisses überschreiben würden... Als weitere Optionen stehen zur Verfügung: --timecheck Sekunde
Gibt eine Warnung aus, wenn der Zeitstempel einer zu packenden Datei älter
als die angegebenen Sekunden ist; somit lassen sich leicht versehentliche
Einträge der Dateiliste aufspüren (das Zeitintervall sollte
größer sein, als der Paketbau dauert)
--clean Entfernt das BUILD-Verzeichnis nach erfolgtem Bau
--rmsource Entfernt die Quellen und die SPEC-Datei nach erfolgtem Bau
--test Simuliert den Bau; anhand der Ausgaben können vorab Fehler erkannt werden
--sign Fügt eine PGP-Signatur ins Paket ein
--target Plattform Spezifiziert die Zielplattform, für die das Paket erzeugt werden soll
--buildroot Verzeichnis Überschreibt den gleichnamigen Eintrag der SPEC-Datei
Beispielhaft sollen die Schritte aufgezeigt werden, die Rpm beim Paketbau mit der Option -ba durchläuft:
Exemplarisch folgt der Aufruf, mit dem wir die Linuxfibel-RPM-Pakete erstellen:
Bei Verzicht auf Angabe der Zielplattform wird diese Information vom C-Compiler (gcc) übernommen (es würde also stets ein Architektur abhängiges Paket erzeugt werden).
HintergrundWährend sich bei der Aktualisierung von Quellcode-Paketen das Patchformat bereits seit langem etabliert hat, werden Updates von RPM-Paketen noch immer als vollständige Pakete bereit gestellt. Leider haben RPM-Pakete, da sie oft Programme und Bibliotheken umfassen, die Eigenschaft, recht umfangreich zu sein. Und insbesondere der Anwender, dessen Rechner nur mit einer lahmen Modemanbindung am Internet teilnimmt, stöhnt bei notwendigen Aktualisierungen. Die SuSE AG hat eine Erweiterung des RPM-Formats vorgeschlagen, um das Patchen derartiger Pakete zu ermöglichen. Dass es funktioniert, beweisen die zahlreichen Patches, die SuSE zu ihren RPM-Paketen bereits anbietet. Bleibt zu hoffen, dass die Erweiterungen bald zum allgemeinen Funktionsumfang von RPM zählen. Wir demonstrieren nachfolgend die Verwendung und Erzeugung solcher Patches. Denken Sie immer daran, dass dies nur mit einem angepassten RPM-Kommando funktioniert. Konsultieren Sie das Manual zum RPM, ob dieses u.a. die Option basedon kennt.
Einspielen eines RPM-PatchesWie auch bei Quelltextpatches kann nicht jeder RPM-Patch auf jedes Paketversion angewandt werden. Für den Fall, dass Sie es dennoch versuchen, würde rpm die Installation abweisen. Mit der eingangs erwähnten Option --basedon können Sie vorab erkennen, ob der Patch für die installierte Version »passend« ist:
Der Patch im Beispiel kann auf installierte tk-Rpm-Pakete der Versionen 8.4-48, 8.4-51 oder 8.4-5 angewandt werden. Wenden Sie übrigens die Option --basedon auf ein »normales« Rpm-Paket an, wird nichts ausgegeben (Was sollte auch ausgegeben werden?). Das Einspielen des Rpm-Patches geschieht analog zur Installation eines »normalen« Rpm-Pakets mittels der Option -i:
Ob ein Rpm-Paket gepatcht ist, erfahren Sie mit Hilfe der Option -P bzw. --patches, die alle ersetzten Dateien auflistet:
Erzeugen eines RPM-Patches
Der feine UnterschiedGäbe es keine Debian-Distribution, so könnte der RedHat Package Manager zu Recht den Anspruch eines Standard-Linux-Paketformats erheben. Und würde Debian nicht ausgerechnet bei eingefleischten Linuxkennern so hoch im Kurs stehen, so würden die häufig erklingenden Aussagen, »das Debian-Paket-Format sei dem von RedHat überlegen«, als Pauschalmeinung von Unwissenden ungehört in der Senke des Vergessens verhallen. Doch was unterscheidet dieses Format so von Rpm, dass die Debianer vortrefflich ob der Vorzüge diskutieren mögen? Als augenscheinlichster Unterschied kommt die Paketverwaltung von Debian mit einer Reihe von Programmen daher, während RedHat's RPM die Funktionalität unter einem Hut vereint. Der Zweck der wesentlichen Werkzeuge sei an dieser Stelle nur kurz vermerkt: dpkg
Es handelt sich quasi um das »Hauptprogramm« der Debian-Paketverwaltung. Dient der
(De)Installation der Pakete, zu dessen Aktualisierung, hilft bei Abfragen und findet außerdem
als Frontend zu dpgk-deb Verwendung. Wir werden uns im folgenden Abschnitt verstärkt an
diesem Werkzeug orientieren, auch wenn die meisten administrativen Tätigkeiten bequem mit
dem Frontend dselect vorgenommen werden können.
dpkg-deb
Erzeugt und verwaltet Debian-Pakete. Obwohl das Kommando separat verwendet werden kann, wird es
zumeist durch dpkg gesteuert.
dselect
Ein interaktives Frontend zu dpkg. deselect modifiziert nur die Aktionen aus
der Datenbank, anhand derer dpkg entsprechende Handlungen vornimmt.
apt-get
Ein Bestandteil des (in Entwicklung befindlichen) »Advanced Package Tools
(APT)«, das als zentrales Paketverwaltungswerkzeug dienen soll. Einige weitere Kommandos
aus APT werden im weiteren Text kurz benannt.
Informationen zu installierten Paketen speichert RPM in einer einzigen Datenbank (»/var/lib/rpm«). Debian hingegen legt seine Verwaltungsdateien in Dateien unterhalb von »/var/lib/dpgk/« ab. In »/var/lib/dpgk/available« stehen alle auf dem System verfügbaren (nicht zwingend installierte) Pakete, »/var/lib/dpkg/status« enthält die ggf. auszuführende Aktion und den Status zu jedem verfügbaren Paket. Der Begriff der Aktion tauchte bereits in der Kurzbeschreibung zu »dselect« auf. Die Paketverwaltung entscheidet anhand dieser Information und dem aktuellen Zustand, wie mit einem Paket zu verfahren ist: u - Unknown Keine Aktion
i - Install Das Paket ist zu installieren
r - Remove Das Paket ist zu deinstallieren; Konfigurationsdateien bleiben erhalten
p - Purge Das Paket ist einschließlich seiner Konfigurationsdateien zu löschen
Die Unterscheidung von »Remove« und »Purge« soll verhindern, dass mühsam angepasste Konfigurationsdateien gelöscht werden, falls das Paket während einer Aktualisierung »zeitweilig« entfernt wird. Der Status zu einem Paket gibt seinen aktuellen Zustand im System an: config-files Einzig die Konfigurationsdateien zu einem Paket sind installiert (bspw. per »remove« gelöscht).
half-configured, half-installed Das Paket ist nicht vollständig konfiguriert/installiert.
installed/not-installed Das Paket ist installiert/nicht installiert.
unpacked Das Paket ist installiert (entpackt), aber nicht konfiguriert.
Enthält ein Paket Installationsskripte, so werden diese zum Zeitpunkt der Installation in einem Verzeichnis »/var/log/dpkg/Paketname« abgelegt. Das Paketformat selbst ist bei RedHat's RPM eine Eigenkreation, das - vereinfacht formuliert - aus dem eigentlichen Datenpaket im *.tgz-Format und den Konfigurationsinformationen besteht. Debian richtet sein Format an dem der statischen Bibliotheken aus, indem die einzelnen Bestandteile per »ar« ins Archiv gelangen. Letztlich landet aber auch das Paket mit den eigentlichen Daten als *.tgz im Archiv. Hinzu kommen die Dateien »debian-binary« mit der Versionsnummer und »control.tar.gz«, die Installationsskripte, eine Beschreibung und die Dateiliste umfasst. Ist die Wertung der bisherigen Differenzen rein eine Frage des persönlichen Geschmacks, so ist Möglichkeit der Verwendung von Wildcards in Anfragen des Debian-Paketsystems ein nicht zu unterschätzender Vorteil. Allgemeine AbfragenEbenso wie bei RPM konsultiert Debian's Paketverwaltung die Datenbankeinträge, um Informationen zu einem Paket zu gewinnen. Da Debian auch den Status nicht-installierter - aber verfügbarer - Pakete in den Datenbanken vorhält, erfolgt auch eine diesbezügliche Recherche nur anhand der Einträge. Die Recherche übernimmt das Kommando dpgk in Verbindung mit der Option -l bzw. in der Langform --list. Eventuell folgende Parameter werden als Paketnamen bzw. Namen mit Wildcards interpretiert. Ein Verzicht auf jegliche Angabe kommt einer Abfrage aller verfügbaren Pakete gleich:
Die einführende Statuszeile beschreibt kurz die einzelnen Felder der Tabelle. In der ersten Spalte steht die zuletzt erwünschte Aktion; Spalte 2 enthält den aktuellen Zustand. In der Beispielabfrage betraf bei allen angeführten Paketen die letzte Aktion deren Installation (i). Dass diese bereits abgeschlossen wurde, markiert im Beispiel das Symbol i der zweiten Spalte. Eine belegte 3. Spalte deutet auf ein Installationsproblem hin. Eventuell benennt das Symbol den konkreten Fehler. Die weiteren Spalten enthalten den Paketnamen, die Versionsnummer sowie eine Kurzbeschreibung zum Paket. Die gezielte Betrachtung nur eines Pakets geschieht durch Angabe seines Namens. Sind nur Bestandteile des Namens bekannt, spielt Debian's Recherche-Vorgehen seine Stärke aus, indem die von den Shells her bekannten Wildcards die Angabe von Namensmustern gestatten. Das folgende Beispiel demonstriert eine Anfrage an alle Pakete mit zweistelligem Namen:
Beachten Sie das in Hochkommata eingeschlossene Suchmuster. So wird eine unerwünschte Interpretation durch die Shell verhindert! Um weiter gehende Informationen zu einem Paket zu erhalten, bedarf es einer Statusabfrage per dpgk -s Paketname. Hierunter finden Sie auch die Abhängigkeiten und Konflikte, die Sie bei RPM erst durch gezielte Einzelabfragen in Erfahrung bringen:
Für den Fall, dass das zu konsultierende Paket nicht installiert ist, benötigen Sie die Optionen -I bzw. --info, um an weiter führende Informationen zu gelangen:
Die Liste der von einem Paket bereit gestellten Dateien erhalten Sie mittels dpgk -L Paketname:
Den umgekehrten Weg, zu einer gegebenen Datei das Paket zu finden, welches diese enthält, ist mit dpgk -S Dateimuster möglich. Im Unterschied zur Abfrage der Dateiliste ist hier die Angabe von Wildcards gestattet:
Abfrage von AbhängigkeitenDie im vorherigen Abschnitt erwähnte Option -s zeigte sowohl die Paketnamen auf, die ein konkretes Paket benötigt als auch jene, deren parallele Installation zu Konflikten führen würde. Auch die Information, was das Paket zur Verfügung stellt, entlockt dpgk -s einem Paket. Wie aber können Sie in Erfahrung bringen, welche Pakete das installierte benötigen? Hier ist dpgk mit seinem Latein am Ende. Das aus den Advanced Package Tools (APT) stammende Kommando apt-cache showpkg Paketname kann helfen:
Welche Pakete die Installation von xterm bedingen, können Sie dem Eintrag »Reverse Depends:« in obigem Beispiel entnehmen. Anmerkung: Apt kennt Recherchen analog zu Rpm's Optionen --requires, --provides und --whatrequires, nicht jedoch zu --whatprovides. Alles in Ordnung?Die Überprüfung der Integrität installierter Dateien geschieht wie auch bei Rpm mittels md5-Prüfsummen. Im Gegensatz zu Rpm erledigt dpkg jedoch nicht selbst die Aufgabe. Die Existenz der Prüfsummen, anhand derer Dateien kontrolliert werden können, liegt allein in der Verantwortung des Paketerstellers. Falls dieser jene überhaupt vorgesehen hat, finden Sie diese im Verzeichnis »/var/lib/dpkg/info« unter Namen »Paketname.md5sum«. Die Überprüfung müssen Sie von Hand vornehmen:
Das Beispiel offenbart ein Problem. Ein erneutes Einspielen des Pakets scheint empfehlenswert. Anmerkung: Die Dateien »/var/lib/dpkg/info/Paketname.md5sums« enthalten alle für md5sum erforderlichen Informationen (zum Paket gehörigen Dateinamen mit deren Prüfsummen). Weitere Überprüfungsmechanismen (Rechte, Eigentümer, Modifikationszeit ..) kennt die Debian-Paketverwaltung nicht. Installation von Deb-Paketen...noch paar einführende Worte finden... Installation und Konfiguration mit »dpgk --install«Die traditionelle Methode zur Installation verwendet das Kommando dpkg. Vorhandene Abhängigkeiten werden zwar erkannt aber nicht aufgelöst, d.h. ein Paket lässt sich stets installieren, selbst wenn es wegen fehlender Vorbedingungen nicht nutzbar sein sollte. Dpkg arbeitet quasi wie Rpm in Verbindung mit den Optionen --nodeps --force.
Sowohl ein einzelnes Paket als auch alle in einem Verzeichnis (einschließlich Unterverzeichnisse bei Angabe der Option »-R«) liegenden Pakete lassen sich mit einem einzigen Befehl installieren. Intern arbeitet dpkg folgende Schritte ab:
Auch hierzu ein Beispiel:
Installation und Konfiguration mit »apt-get»dpgk lässt eine Eigenschaft schmerzlich vermissen: die automatische Auflösung von Abhängigkeiten. Aus diesem Grund ist apt-get oft erste Wahl bei den Werkzeugen zur Paketinstallation. Intern deligiert apt-get die Arbeit jedoch auch nur an geeignete dpkg-Aufrufe.
Damit apt-get seine Arbeit verrichten kann, benötigt es Kenntnis über alle zur Installation zur Verfügung stehenden Pakete. Hierzu sind sämtliche Quellen (CDROM, ein FTP-Verzeichnis, Verzeichnisse mit Paketen auf lokalen Platten...) in die Datei »/etc/apt/sources.list/« einzutragen. Hierzu können Sie sich eines Editors bedienen oder die Oberfläche von apt-setup verwenden. Apt-get scannt sämtliche Quellen und kann anhand der resultierenden Paketliste entscheiden, ob die Abhängigkeiten bei der Installation eines Pakets erfüllt werden können. Ist dies der Fall, so wird das Kommando sowohl das Paket als auch alle von diesem benötigten Pakete selbsttätig installieren. Bei Nichterfüllung bricht die Installation ab.
Anstatt des konkreten Paketnamens können Sie bei apt-get sogar Namensmuster mit den Shell-üblichen Wildcards angeben (Schützen Sie diese vor der Auswertung durch die Shell!). Das Kommando wird alle Pakete, auf deren Name das Muster zutrifft, installieren. Eine Liste alle verfügbaren Pakete erhalten Sie mittels »apt-cache dump-avail«. Etwas mehr Komfort bieten dselect und das noch in einem frühen Entwicklungsstadium steckende Programm aptitude, die wir hier nicht behandeln werden. Installation ohne Konfiguration mit »dpgk --unpack»
Die Option --unpack arbeitet wie -i mit dem einzigen Unterschied, dass der abschließende Schritt der Konfiguration des neuen Pakets ausgelassen wird.
Eine nachträgliche Konfiguration ist möglich und wird im nachfolgenden Abschnitt beschrieben. Konfiguration und Reparatur installierter PaketeErfolgte eine Installation ohne anschließender Konfiguration eines Pakets, können Sie letzteren Schritt nachholen, indem Sie »dpkg --configure Paketname« ausführen:
Fehlerhafte Installationen identifizieren Sie anhand der Statusspalten beim Listing eines Pakets:
»H« weist auch eine unvollständige Installation hin. Mit »R« wird eine erneute Installation empfohlen, um das Problem zu beheben:
Die Statusspalten sollten sich bei Erfolg folgendermaßen präsentieren:
Entfernen von Deb-PaketenAuch zum Entfernen von Paketen werden wir die Verwendung der beiden Alternativen dpkg und apt-get demonstrieren. Beide Kommandos ermöglichen auf Wunsch das Beibehalten bestehende Konfigurationsdateien, was mitunter bei späterem Wiedereinspielen von Paketen deren Administrationaufwand vermindern kann. Mit Erhalt der Konfigurationsdateien mit »dpkg -r«
Mit Erhalt der Konfigurationsdateien mit »apt-get remove«
Inklusive der Konfigurationsdateien mit »dpkg -P«
Inklusive der Konfigurationsdateien mit »apt-get --purge remove«
Nachträgliches Entfernen der KonfigurationsdateienHaben Sie die Pakete bereits gelöscht und deren Konfigurationsdateien seinerzeit beibehalten, so müssen Sie auf »dpkg« zurückgreifen, um auch die Konfigurationsdateien aus dem System zu verbannen. Wir demonstrieren die Arbeitsverweigerung von »apt-get --purge«:
Wir werden das Thema nicht erschöpfend abhandeln, insbesondere verzichten wir auf die registrierenden Schritte zum Erhalt des Status eines offiziellen Debian-Pakets. Als Ergebnis der folgenden Abschnitte wird ein Debian-konformes Paket der Linuxfibel stehen. Aufbau von Deb-PaketenNamenskonventionDie Namenswahl von (offiziellen) Debian-Paketen ist fest vorgegeben:
Die Releasenummer ist gleichbedeutend mit der Versionsnummer der Paketerstellung. Der Aufbau eines DebianpaketsEines der gebräuchlichsten Kommandos ist sicherlich tar - der Tape-Archiver. Sie haben es sicherlich schon verwendet, um Dateien und Verzeichnisse in eine einzelne Datei zu packen oder selbige aus einem tar-Archiv zu extrahieren. Im Grunde genommen kennen Sie somit bereits den Aufbau von Debian-Paketen: Sie sind nichts anderes als Archive, die eine Sammlung von Dateien und Verzeichnisse beinhalten. Anstelle des tar-Archivs tritt nun das ar-Archiv, anstelle des Kommandos tar tritt ar, das fast dieselben Optionen wie das bereits bekannte Kommando kennt. Betrachten Sie den Inhalt eines beliebigen Debian-Pakets:
Das Entpacken der Dateien erolgt erfolgt analog zur Option des tar-Kommandos mit x:
Die Dateien eines Debian-Paketsdebian-binary
Die Datei beschreibt die Version des verwendeten Formats der Debian-Datei. Im Beispiel verwenden wir die derzeit aktuelle Version 2.0. Wichtig ist, dass der Eintrag der Versionsnummer mit einem Zeilenumbruch abgeschlossen wird. control.tar.gz
Das Paket der Kontrolldateien umfasst mindestens die Datei control mit der Beschreibung des Pakets. Die Datei dient u.a. zur Versionsprüfung und Abhängigkeitsverifizierung. Sie können ebenso dpkg -p konsultieren, um folgende Ausgabe zu erhalten:
Optionale Dateien im Kontrollpaket sind die Skripte, die unmittelbar vor bzw. nach einer (De)Installation auszuführen sind. Die Namen der Skripte sind mit preinst, prerm, postinst und postrm fest vorgegeben. Jedes der Skripte kann mit konkreten Parametern aufgerufen werden, sodass eine Steuerung des Skriptablaufs nach gewähltem (De)Installationskontext möglich wird. Die wichtigsten Parameter sind:
Im Debian Policy Manual (Chapter 6 - Package maintainer scripts and installation procedure) können Sie sich über die weiteren Parameter informieren. Ein Skript sollte bei Fehler freiem Ablauf mit dem Wert 0 zurück kehren und mit einem Wert ungleich 0 sonst. Gehören Konfigurationsdateien zu einem Paket, so werden deren Namen inklusive Pfadangaben in der Datei conffiles hinterlegt:
Die Unversehrheit der Dateien in einem Paket kann anhand des Inhalts einer Datei md5sums verifiziert werden, insofern die Paketbauer diese sinnvolle Eigenschaft vorgesehen hatten:
data.tar.gz Dieses Archiv enthält die eigentlichen Paketdateien (Programme, Dokumentationen, Konfigurationsdateien...). Die Linuxfibel als Debian-PaketNach den allgemein gehaltenen Vorbetrachtungen vollführen wir den Schritt zum Debian-Paket anhand des konkreten Beispiels der Linuxfibel. Vorbereitung der UmgebungZunächst benötigen wir ein Verzeichnis, indem der Paketbau vollzogen werden kann. Prinzipiell kann das Verzeichnis irgendwo im Dateisystem liegen und beliebig benannt sein. In Analogie zu Rpm sammeln wir sämtliche Pakete unterhalb eines Verzeichnisses »/usr/src/deb«:
In das Unterverzeichnis DEBIAN gelangen später die Beschreibungsdateien und (De)Installations-Skripte. Kopieren der DateienIn das neue Arbeitsverzeichnis sind alle Dateien zu kopieren, die zum Paket gehören sollen. Im Fall der Linuxfibel sind das die HTML-Dateien und die Bilder. Wir gehen nachfolgend davon aus, dass im Verzeichnis »/usr/share/doc/linuxfibel« unseres Systems all jene Dateien liegen, die das fertige Paket umfassen soll:
Anlegen der KontrolldateienSämtliche Kontrolldateien und Skripte gehören in das Verzeichnis DEBIAN unterhalb des Build-Verzeichnisses. debian-binary Hier hinein gehöert die Versionsnummer des verwendeten Paketformats
control Der im Beispiel verwendete Inhalt der Datei »control« umfasst die minimal erforderlichen Einträge.
Wichtige Einträge darüber hinaus sind: Depends
Erfordert Ihr Paket die Installation weiterer Software, so können Sie diese hier inklusive der notwendigen
Version angeben. Dem Namen des Softwarepakets folgt die in runde Klammern anzugebende Version. Weitere Softwarepakete
schließen sich, durch Kommata voneinander getrennt, an ("gcc (>=3.2), glibc (>> 2.2)").
Conflicts
Steht Ihr Paket in Konflikt mit anderen (sodass beide nicht gleichzeitig installiert sein sollten), so können Sie
auch dieses in der Kontrolldatei vermerken. Die Syntax eines Eintrags ist analog zu Depends.
Replaces
Ist das Paket ein vollständiger Ersatz für ein anderes, kann der Name des zu ersetzenden Pakets hier angegeben
werden.
Provides
Hier steht ein virtueller Paketname, der eine Einordnung in eine Anwendungsgruppe ermöglichen soll. Somit kann der Anwender
in Installationsprogrammen (bspw. dselesct) aus einer Reihe von Programmen auswählen, die nahezu dasselbe tun.
Installed-Size Angabe der Paketgröße.
md5-Prüfsummen Wir statten unser Paket mit MD5-Prüfsummen über jede der Dateien aus:
Der eigentliche BauHierfür wechseln Sie aus dem Build- in das übergeordnete Verzeichnis. Rufen Sie dpkg-deb mit der Option --build und dem Namen des Buildverzeichnisses als Argument:
Das fertige Paket liegt als »linuxfibel.deb« vor. Wir prüfen dessen Kontrolldatei:
Um der Namenskonvention für Debian-Pakete zu entsprechen, ist das Paket noch umzubenennen:
Falls ein Programm nicht in einem von »meiner« Distribution unterstützten Format vorliegt, so kann eine Formatwandlung eine Installation doch noch ermöglichen. Als Voraussetzung für den Einsatz des Perl-Skripts alien müssen die Programme zur Verwaltung der »Fremdformate« installiert sein, also:
Eine Paketverwaltung für ein SystemAuch wenn die Programme zur direkten Installation von »Fremdpaketen« vorhanden sind, sollten Sie diese niemals zum Installieren verwenden! Paketverwaltungen basieren auf einer Datenbank und jede Verwaltung verwendet ihre eigene. Leider wissen die Programme nichts von der Existenz der »Konkurrenz«, sodass Vorteile wie Berücksichtigung von Abhängigkeiten, Paketaktualisierung, sauberes Entfernen usw. nicht mehr gegeben sind. Des Weiteren ist eine Wandlung oft mit einem Verlust an Information behaftet. Deb- und Rpm-Pakete unterscheiden sich im internen Aufbau, sodass manche Aspekte bei der Konvertierung nicht berücksichtigt werden können. Das Tgz-Format beinhaltet gar nur die zu installierenden Dateien ohne jegliche Hinweise auf Version, Abhängigkeiten... Eine Wandlung von Tgz in ein anderes Format ermöglicht einzig die (De)Installation der Daten, aber mehr auch nicht! Und so gehts...ie Handhabung von alien gestaltet sich spielend einfach. Das Format des Eingabepakets ermittelt das Programm anhand dessen Struktur. Ohne Angabe weiterer Argumente wird das Debian-Format erzeugt. Alternative Formate sind:
Das nachfolgende Beispiel wandelt das Linuxfibel-Basis-RPM-Paket in das Tgz-Format:
Die Warnung ist nicht weiter tragisch. Sie weist nur darauf hin, dass die erzeugte Datei nicht Root gehört und somit ein Sicherheitsrisiko darstellen könnte (da nicht nur Root das Paket bearbeiten darf). Das Erzeugen von deb-, rpm- oder slp-Formaten bleibt dann aber einzig Root vorbehalten. Um ein Format von alien lesen bzw. schreiben zu können, muss das entsprechende Werkzeug (bspw. rpm oder debmake) installiert sein. Natürlich kann eine solche Konvertierung nicht sämtliche Informationen sauber in ein Paket integrieren, die diese »normalerweise« enthalten würde. Gerade die Erzeugung der ausgereiften rpm- oder deb-Formate aus einem Tape Archiv kann nur eine saubere (De)Installation der Dateien garantieren. Abhängigkeiten o.Ä. bleiben vollends unberücksichtigt:
Zumindest die fehlende Paketbeschreibung kann bei Konvertierung aus dem tgz-Format per Kommandozeile ergänzt werden. Geben Sie hierzu die Option --description=Text an. Auch können Sie das Paket unverzüglich installieren, indem Sie die Option -i verwenden.
Mit dem Einspielen von Bibliotheken ins System ist es oft noch nicht getan. Was nützt es, wenn ein Programm abbricht, weil es »seine« Bibliotheken nicht finden kann? Zunächst bedarf es eines kleinen Ausflugs, wie in Unix der Umgang mit Bibliotheken erfolgt. Nachfolgend diskutieren wir die Möglichkeiten, um Fehlerausgaben, wie die Folgende, zu vermeiden:
Statisch, dynamisch, sharedEin erster naiver Erklärungsversuch könnte »statisch« mit »unveränderbar« gleich setzen. Hieraus ließe sich schlussfolgern, dass dynamisch gelinkte Programme sich ändern (können), doch zum Glück ist dem dann doch nicht so. Gebräuchlicher ist die Umschreibung eines statisch gelinkten Programms als ein Programm, das zur Laufzeit eine konstante Größe an Hauptspeicher verkonsumiert. Aus diesem Blickwinkel betrachtet, wäre der Speicherbedarf dynamischer gelinkter Programme änderbar. Und tatsächlich entspricht diese Betrachtungsweise dem wahren Wesen statisch bzw. dynamisch gelinkter Programme. Dem statisch gelinkten Programm wurde die komplette Funktionalität bereits zur Kompilierzeit einverleibt. Es ist unabhängig von jeglichen Bibliotheken und somit prinzipiell auf jedem System lauffähig, das das Programmformat unterstützt. Das dynamisch gelinkte Programm beinhaltet anstatt »verbreiteter« Funktionen nur die Schnittstellen zu diesen; die Funktionen selbst liegen in Form von Bibliotheksroutinen vor. Es ist klar, dass das dynamisch gelinkte Programm i.d.R. weniger Platz auf der Festplatte beansprucht, als es ein statisch gelinktes Pedant tut, das dieselbe Funktionalität erfüllt. Der Nutzen der dynamischen Realisierung wird erst recht deutlich, wenn man die Gemeinsamkeiten zahlreicher Programme betrachtet. So greift nahezu jedes Programm auf Routinen der Ein- und Ausgabe zu, die meisten Programme verwenden eine dynamische Speicherverwaltung usw. Kandidaten für Funktionen, die besser in Bibliotheken realisiert werden sollten, finden sich reichlich und tatsächlich existieren in einem Linuxsystem nur noch wenige statisch gelinkte Programme (der dynamische Linker ist eines davon). Die dynamisch gelinkten Programme bedingen jedoch die Anwesenheit der benötigten Bibliotheken. Je nach Zeitpunkt, wann eine Bibliothek geladen wird, werden »dynamisch ladbare« und »geteilte« (engl.: shared) Bibliotheken unterschieden. Diese begriffliche Trennung ist etwas unglücklich, da sich beide Bibliothekenstypen nicht unterscheiden. Ob sie nun als dynamisch ladbare oder als shared Bibliothek fungieren, hängt einzig vom Funktionsaufruf des Programms ab. Lädt dieses eine Bibliotheksfunktion als »shared«, so wird die Bibliothek zum Zeitpunkt des Ladens des Programms in den Hauptspeicher geladen (falls ein anderes Programm diese Bibliothek bereits geladen hatte, entfällt dieser Schritt). Im Falle eines »dynamischen« Aufrufs erfolgt das Laden erst, wenn tatsächlich auf eine Funktion aus dieser Bibliothek zugegriffen wird. Um noch einmal auf den Unterschied zwischen statisch und dynamisch gelinkten Programmen einzugehen, so lässt sich ein weiterer Vorteil der Bibliotheken nennen. Sie sind durch andere Versionen austauschbar, solange die Schnittstellen der Funktionen und die Datenstrukturen beibehalten werden. Somit ist es bspw. möglich, einer grafischen Anwendung unter X ein anderes Aussehen zu verleihen, indem einfach die zuständige Grafikbibliothek gewechselt wird. Ein Übel verbirgt sich dennoch bei dynamisch gelinkten Programmen. Ohne die benötigten Bibliotheken sind sie nicht lauffähig. Der nächste Schritt, die Bibliotheken ins System einzuspielen, genügt meist nicht. Das Programm muss sie auch noch finden können... Wie sucht ein Programm dynamische Bibliotheken?Das Aufspüren der Bibliotheken obliegt einem dynamisch gelinkten Programm selbst. Hierzu beinhaltet es den Dateinamen des dynamischen Linkers ld-linux.so.2 (Glibc2) zu Beginn seines Programmkodes:
ld-linux.so.2 selbst zeigt als symbolischer Link auf die aktuelle Version des Linkers. Startet das Programm, lädt der Kernel diesen dynamischen Linker. Jede dynamische Bibliothek, die ein Programm verwendet, hinterlässt in diesem seinen so genannten »so-Namen«. Dabei handelt es sich um den Präfix lib, gefolgt vom Namen der Bibliothek, wiederum gefolgt von .so. und der Hauptversionsnummer (bspw.: libXt.so.6). Im Dateisystem selbst ist eine dynamische Bibliothek unter ihrem so-Namen, gefolgt von einer Nebenversionsnummer und einer optionalen Patchnummer gespeichert (bspw.: libXt.so.6.1.1). Der dynamische Linker akzeptiert die Anforderung einer Bibliothek, wenn die so-Namen übereinstimmen. Denn eine abweichende Hauptversionsnummer bedeutet eine geänderte Schnittstelle, womit ein Programm mit einer solchen Bibliothek nicht zusammenarbeiten kann. Der Linker lädt nun die geforderte Bibliothek - falls sie nicht schon dort ist - in den Hauptspeicher. Er kennt nun die relative Lage (Adresse) der Funktionen und Variablen, die das Programm aus der Bibliothek benötigt und manipuliert die Verweise in der »Global Offset Table« (globale Variablen) bzw. in der »Procedure Linkage Table« (Funktionen) des Programms. Zur Suche einer Bibliothek bedient sich der Linker mehrfacher Mechanismen. Zunächst darf ein dynamisch gelinktes Programm auch die kompletten Pfade zu den Bibliotheken eingebunden haben, womit der Linker genau diese verwenden wird. Ein solches Vorgehen erschwert u.a. die Installation von Programmen einer Distribution auf einem »Fremdsystem«, sodass i.d.R. darauf verzichtet wird. Als nächstes betrachtet der Linker den Inhalt verschiedener globaler Umgebungsvariablen. Selten von den Distributionen angewandt - aber möglich - ist die Belegung der Variablen LD_PRELOAD mit den vollständigen Pfadangaben zu Bibliotheken, die vor allen anderen zu laden sind. Somit ist es denkbar, konkrete Funktionen aus anderen Bibliotheken zu überschreiben, da der Linker eine einmal geladene Funktion nicht wieder überschreibt. Aus Sicherheitsgründen wird das Verfahren bei setuid/setgid-Programmen nur zugelassen, wenn Benutzer-ID (UID) und effektive Benutzer-ID (EUID) - bez. Gruppen-ID (GID) - und effektiver Gruppen-ID (EGID) übereinstimmen. In der Praxis setzen vor allem Speicherleck-Prüfprogramme auf den PRELOAD-Mechanismus auf, um (De)Allokationsroutinen durch eigene Versionen zu überladen. Vor den Standardpfaden werden auf der Suche nach dynamischen Bibliotheken anschließend die in der Umgebungsvariablen LD_LIBRARY_PATH aufgeführten Pfade betrachtet. Schließlich kommen die Bibliotheken aus den Standardpfaden zum Zuge. Aus Gründen der Effizienz erfolgt die Suche nicht in den Pfaden aus /etc/ld.so.conf sondern einzig in der Datei /etc/ld.so.cache, die eine Liste aller Bibliotheken aus diesen Pfaden enthält. Das Erzeugen dieser Cache-Datei obliegt dem Kommando ldconfig, das uns später noch interessieren soll. Test mit lddNatürlich wird der Aufruf eines Programms, das eine Bibliothek vermisst, den Namen dieser ausgeben, womit fehlende Abhängigkeiten automatisch ans Licht gelangen. Darüber hinaus gestattet das Kommando ldd aber auch einen Einblick in die bereits erfüllten Voraussetzungen, indem es zu den auf der Kommandozeile angegebenen Programmen oder Bibliotheken die benötigten Bibliotheken ausgibt:
Die im Beispiel angewandte Option -v gibt einige erweitere Informationen preis. Konfiguration des dynamischen LinkersWie bereits erwähnt, wird die Arbeitsweise des Linkers sowohl durch Umgebungsvariablen als auch durch die Datei /etc/ld.so.cache beeinflusst. Letztere Datei wiederum wird durch das Programm ldconfig erzeugt, welches in /etc/ld.so.config konfiguriert wird. Somit bieten sich bei der Installation neuer Bibliotheken zwei Wege an, damit der Linker diese in Zukunft finden kann:
Die Belegung von LD_LIBRARY_PATH ist die »schnelle Methode«, wenn ein Programm mal eben getestet werden soll und das Laden der Bibliothek durch den Linker scheitert, weil dieser sie nicht finden kann. Ansonsten hängt diesem Vorgehen derselbe Nachteil an, der zum Caching-Mechanismus führte: eine Suche im Dateisystem kostet Zeit. Ein Vorteil wäre dennoch zu nennen: mittels LD_LIBRARY_PATH darf jeder Benutzer Einfluss auf den Linker nehmen, während eine Manipulation von /etc/ld.so.cache einzig dem Administrator vorbehalten ist. Die Syntax zur Belegung der Variablen erfolgt analog zur Variablen PATH. Um die Cache-Datei /etc/ld.so.cache des Linkers zu aktualisieren, genügt nach der Installation neuer Bibliotheken zumeist ein Aufruf von ldconfig:
ldconfig durchsucht zuerst die Verzeichnisse /usr/lib und /lib und nachfolgend alle in der Datei /etc/ld.so.conf aufgeführten Pfade. Zu jeder gefundenen neuen Bibliothek erzeugt ldconfig selbsttätig den symbolischen Link des so-Namens auf den Bibliotheksnamen (also bspw. libX.so.6 als Link auf libX.so.6.1) und aktualisiert die Datei /etc/ld.so.cache. Das Erzeugen des Links kann mittels der Option -l verhindert werden. Mit -n Pfad[e] werden einzig die angegebenen Verzeichnisse betrachtet (also auch nicht /usr/lib und /lib). Eine Konfiguration ist - wenn überhaupt - nur durch Hinzufügen weiterer Suchpfade in die Datei /etc/ld.so.conf erforderlich. Jeder Pfad erscheint in dieser auf einer eigenen Zeile:
Vergessen Sie nicht, nach Manipulation dieser Datei die Änderung durch Aufruf von ldconfig auch zu aktivieren. Auch sollten Sie beachten, dass die Pfade in der aufgeführten Reihenfolge durchsucht und bei gleichnamigen Bibliotheken stets nur die »erste« gefunden wird. Wohl eher für Entwickler interessant ist die Datei /etc/ld.so.preload, die eine Liste durch Leerzeichen getrennter Bibliotheken enthält, welche vor allen anderen Bibliotheken geladen werden. Analog zur Variablen LD_PRELOAD ist somit das Überschreiben einzelnen Funktionen möglich. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Korrekturen, Hinweise? |