Integration von Software |
Übersicht |
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.
Source-Pakete |
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.
user@sonne> tar xzf galeon-0.9pre3.tar.gz user@sonne> cd galeon-0.9pre3 user@sonne> ls ABOUT-NLS INSTALL TODO configure install-sh po AUTHORS Makefile.am acconfig.h configure.in intl src COPYING Makefile.in aclocal.m4 galeon.desktop macros stamp-h.in COPYING.README NEWS anim galeon.gnorba missing ui ChangeLog README autogen.sh galeon.spec mkinstalldirs FAQ THANKS config.h.in galeon.spec.in myportal.css |
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.
Befindet 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:
user@sonne> ./configure creating cache ./config.cache checking for a BSD compatible install... /usr/bin/ginstall -c checking whether build environment is sane... yes checking whether make sets ${MAKE}... yes checking for working aclocal... found checking for working autoconf... found checking for working automake... found checking for working autoheader... found checking for working makeinfo... found checking for gnome-config... /opt/gnome/bin/gnome-config ... checking for Mozilla... no configure: error: *** Mozilla 0.7 is required *** A package for 0.7 is available here: *** http://people.redhat.com/blizzard/software/. |
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.
user@sonne> ./configure --help Usage: configure [options] [host] Options: [defaults in brackets after descriptions] Configuration: --cache-file=FILE cache test results in FILE --help print this message --no-create do not create output files --quiet, --silent do not print `checking...' messages --version print the version of autoconf that created configure Directory and file names: --prefix=PREFIX install architecture-independent files in PREFIX [/usr/local] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [same as prefix] --bindir=DIR user executables in DIR [EPREFIX/bin] ... |
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:
user@sonne> ./configure ... creating Makefile user@sonne> |
Bei 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:
user@sonne> make cd /home/user/galeon-0.9pre3/src ... |
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:
In file included from foobar.c:2: /opt/gnome/include/gnome.h:12: gnomesupport.h: 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:
Die 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:
user@sonne> locate gnomesupport.h /opt/gnome/lib/gnome-libs/include/gnomesupport.h user@sonne> export C_INCLUDE_PATH=$(C_INCLUDE_PATH):/opt/gnome/lib/gnome- libs/include |
Im 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).
Es 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.
root@sonne> ln -s /opt/gnome/lib/gnome-libs/include/gnomesupport.h /usr/include/ |
/usr/i486-suse-linux/bin/ld: cannot find -lgnome collect2: ld returned 1 exit status |
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):
user@sonne> locate libgnome.a /opt/gnome/lib/libgnome.a user@sonne> export LIBRARY_PATH=$(LIBRARY_PATH):/opt/gnome/lib |
/opt/gnome/lib/libgnome.a(gnome-config.o): In function `_gnome_config_set_vector': gnome-config.o(.text+0x2630): undefined reference to `g_free'/ |
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...
Die 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:
root@sonne> make install |
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.
Nur 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:
# Nur selten bietet ein Makefile dieses... root@sonne> make uninstall |
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...
Patch |
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.
Nichts 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:
user@sonne> cat ErsteVersion.txt Ein einfaches Beispiel, um die Arbeitsweise von "patch" zu demonstrieren. |
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:
user@sonne> cat ZweiteVersion.txt Dies ist ein einfaches Beispiel, um die Arbeitsweise von "patch" zu demonstrieren. |
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:
user@sonne> diff -u ErsteVersion.txt ZweiteVersion.txt --- ErsteVersion.txt Wed Apr 25 21:06:20 2001 +++ ZweiteVersion.txt Wed Apr 25 21:06:42 2001 @@ -1,3 +1,3 @@ -Ein einfaches Beispiel, +Dies ist ein einfaches Beispiel, um die Arbeitsweise von "patch" zu demonstrieren. |
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:
user@sonne> diff -u ErsteVersion.txt ZweiteVersion.txt > patch_ErsteVersion |
Bei umfangreichen Patchdateien lohnt sich das Komprimieren derselben.
user@sonne> gzip patch_ErsteVersion user@sonne> ls patch_ErsteVersion.gz |
Die 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:
user@sonne> ls ErsteVersion.txt user@sonne> gunzip -c patch_ErsteVersion.gz | patch patching file ErsteVersion.txt |
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:
user@sonne> pwd /home/user/sonstwo user@sonne> gunzip -c ../linuxfibel-0.6.0-0.7.0.patch.gz | patch can't find file to patch at input line 4 Perhaps you should have used the -p or --strip option? The text leading up to this was: -------------------------- |diff -u -r --new-file fibel_old/access.htm linuxfibel/access.htm |--- fibel_old/access.htm Sun May 6 17:14:57 2001 |+++ linuxfibel/access.htm Fri Jun 29 15:08:22 2001 -------------------------- File to patch: |
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:
user@sonne> for i in `find . -name "*.orig"`; do mv $i ${i%*.orig}; done |
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...
Exemplarisch 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:
user@sonne> diff -u -r --new-file fibel_old linuxfibel > linuxfibel-0.6.0-0.7.0.patch user@sonne> ls -l linuxfibel-0.6.0-0.7.0.patch -rw-r--r-- 1 user users 2141291 Jul 5 16:44 linuxfibel-0.6.0-0.7.0.patch user@sonne> gzip -9 linuxfibel-0.6.0-0.7.0.patch user@sonne> ls -l linuxfibel-0.6.0-0.7.0.patch -rw-r--r-- 1 user users 363441 Jul 5 16:49 linuxfibel-0.6.0-0.7.0.patch |
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:
# vermutlich darf nur Root in /usr/share/doc/linuxfibel schreiben... root@sonne> cd /usr/share/doc/linuxfibel root@sonne> gunzip -c ~user/linuxfibel-0.6.0-0.7.0.patch.gz | patch -p1 patching file access.htm patching file allekapitel.htm patching file anxious.htm patching file archiv.htm ... |
Tar-Archive |
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:
root@sonne> tar tzf SoftwarePaket.bin.tgz ./SoftwarePaket/README ./SoftwarePaket/INSTALL ./SoftwarePaket/bin/proggy ... |
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...
Rpm-Pakete |
Sowohl 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.:
Sämtliche Abfragen werden durch die Option -q (query) eingeleitet:
rpm -q [Optionen] |
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:
user@sonne> rpm -qa aaa_base-2000.7.24-4 aaa_dir-2000.7.29-0 aaa_skel-2000.7.16-1 at-3.1.8-225 ... |
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:
user@sonne> rpm -q cpio # Paketname cpio-2.4.2-237 user@sonne> rpm -q cpio-2.4.2 # Paketname + Version cpio-2.4.2-237 user@sonne> rpm -q cpio-2.4.2-237 # Paketname + Version + Revision cpio-2.4.2-237 |
Bezieht sich eine Anfrage auf eine RPM-Datei, so ist neben deren Namen die Option -p zu verwenden:
user@sonne> rpm -q linuxfibel_basis*rpm # -p fehlt! Paket linuxfibel_basis-0.6-0.i386.rpm ist nicht installiert user@sonne> rpm -qp linuxfibel_basis*rpm linuxfibel_basis-0.6-0 |
Beachten Sie, dass sich der Name einer Rpm-Datei nicht zwingend mit dem Namen des Pakets decken muss!
Mit 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:
user@sonne> rpm -qld ext2fs /usr/share/doc/packages/ext2fs/RELEASE-NOTES /usr/share/info/libext2fs.info.gz /usr/share/man/man1/chattr.1.gz /usr/share/man/man1/lsattr.1.gz /usr/share/man/man1/uuidgen.1.gz /usr/share/man/man8/badblocks.8.gz /usr/share/man/man8/debugfs.8.gz /usr/share/man/man8/dumpe2fs.8.gz /usr/share/man/man8/e2fsck.8.gz /usr/share/man/man8/e2label.8.gz /usr/share/man/man8/fsck.8.gz /usr/share/man/man8/mke2fs.8.gz /usr/share/man/man8/mklost+found.8.gz /usr/share/man/man8/tune2fs.8.gz |
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:
user@sonne> rpm -qf /usr/bin/chattr ext2fs-1.18-125 |
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:
user@sonne> rpm -q --specfile linuxfibel_basis.spec linuxfibel_basis-0.6-0 |
Tiefer in den Gründen des Pakets forscht die Option -i, die neben den bereits genannten Informationen Weiteres zum Inhalt offenbart:
user@sonne> rpm -qi ext2fs Name : ext2fs Relocations: (not relocateable) Version : 1.18 Vendor: SuSE GmbH, Nuernberg, Germany Release : 125 Build Date: Sam 29 Jul 2000 16:33:15 CEST Install date: Die 27 Mär 2001 19:47:57 CEST Build Host: Euklid.suse.de Group : System Environment/Base Source RPM: ext2fs-1.18-125.src.rpm Size : 519223 License: Remy Card, Theodore Ts'o Packager : feedback@suse.de Summary : Utilities for the second extended file system Description : Utilities needed to create and maintain ext2 filesystems under Linux. Included in this package are: chattr, lsattr, mke2fs, mklost+found, tune2fs, e2fsck, and badblocks. Authors: -------- Remy Card <card@masi.ibp.fr> Theodore Ts'o <tytso@mit.edu> SuSE series: a |
Um den Status der zu einem Paket gehörigen Dateien zu erfahren, bedienen Sie sich der Option -s:
user@sonne> rpm -qfs /sbin/fsck normal /lib/libcom_err.so.2 normal /lib/libcom_err.so.2.0 normal /lib/libe2p.so.2 normal /lib/libe2p.so.2.3 ... |
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.
Es 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.
user@sonne> rpm -q --requires rsync /bin/sh /usr/bin/perl ld-linux.so.2 libc.so.6 libc.so.6(GLIBC_2.0) libc.so.6(GLIBC_2.1) |
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:
user@sonne> rpm -q --whatprovides /bin/sh bash-2.04-30 user@sonne> rpm -q --whatprovides /usr/bin/perl perl-5.005_03-182 |
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:
user@sonne> rpm -q --provides rsync rsync |
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:
user@sonne> rpm -q --whatrequires /usr/bin/perl aaa_base-2000.7.24-4 groff-1.16-26 lilo-21-132 ps-2000.7.16-4 rpm-3.0.4-68 texinfo-4.0-112 util-2.10m-41 ... |
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...
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:
user@sonne> rpm -q --dump ext2fs | head /lib/libcom_err.so.2 17 964881186 0120777 root root 0 0 0 libcom_err.so.2.0 /lib/libcom_err.so.2.0 8133 964881186 c682f94b908a606d053430e2a8078669 0100755 root root 0 0 0 X /lib/libe2p.so.2 13 964881187 0120777 root root 0 0 0 libe2p.so.2.3 /lib/libe2p.so.2.3 17466 964881187 709a01c3824feccf4b3b35090211902f 0100755 root root 0 0 0 X /lib/libext2fs.so.2 16 964881187 0120777 root root 0 0 12296 libext2fs.so.2.4 /lib/libext2fs.so.2.4 83724 964881187 3ea426260c3f6c02b629bec7ba636ae6 0100755 root root 0 0 41476 X /lib/libss.so.2 12 964881186 0120777 root root 0 0 0 libss.so.2.0 /lib/libss.so.2.0 22186 964881186 203ab396745ad6160e318c024734da3d 0100755 root root 0 0 0 X /lib/libuuid.so.1 14 964881187 0120777 root root 0 0 0 libuuid.so.1.2 /lib/libuuid.so.1.2 11889 964881187 2447a19ed4091e1a22541f1fa2d2e8cb 0100755 root root 0 0 3405 X |
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.
user@sonne> rpm -V xf86 ......G. /usr/X11R6/bin S.5....T /usr/X11R6/bin/SuperProbe ......GT /usr/X11R6/bin/Xmark S.5...GT /usr/X11R6/bin/appres S.5...GT /usr/X11R6/bin/atobm ... |
Der Punkt steht hierbei für einen bestandenen Test, die Buchstaben - bzw. die eine Ziffer - kodiert den Grund für ein Scheitern:
S | Abweichende Dateigröße |
M | Die Rechte oder der Dateityp wurden verändert |
5 | Die MD5-Prüfsumme stimmt nicht |
D | Eine Gerätedatei hat sich verändert |
L | Ein symbolischer Link zeigt auf eine andere Datei |
U | Der Eigentümer hat sich geändert |
G | Die besitzende Gruppe hat sich geändert |
T | Datei besitzt andere Modifikationszeit |
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:
user@sonne> rpm --checksig linuxfibel_basis-0.6.i386.rpm linuxfibel_basis-0.6-0.i386.rpm: md5 OK |
»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:
root@sonne> rpm -U --replacepkgs linuxfibel_basis-0.5.i386.rpm |
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:
root@sonne> rpm --setperms linuxfibel_basis-0.5.i386.rpm |
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:
# Erzeugen einer neuen Datenbank root@sonne> rpm --initdb # Aktualisieren einer bestehenden Datenbank root@sonne> rpm --rebuilddb |
In beiden Fällen kann per --dbpath ein zu /var/lib/rpm abweichende Pfad zur Datenbank angegeben werden.
rpm -i [Optionen] <Paket> rpm -U [Optionen] <Paket> rpm -F [Optionen] <Paket> |
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:
root@sonne> rpm -i linuxfibel_basis-0.6.i386.rpm # oder... root@sonne> rpm -U linuxfibel_basis-0.6.i386.rpm |
Existiert das Paket hingegen bereits, scheitert -i:
# linuxfibel_basis wurde bereits installiert... root@sonne> rpm -i linuxfibel_basis-0.6.i386.rpm Fehler... |
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:
root@sonne> rpm -Uhv linuxfibel_basis-0.6.i386.rpm linuxfibel_basis ####################################### |
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:
root@sonne> rpm -U --oldpackage linuxfibel_basis-0.5.i386.rpm |
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:
root@sonne> rpm -U --relocate /usr/share/doc/linuxfibel=/usr/local/httpd/htdocs linuxfibel_basis-0.6-0.i386.rpm path /usr/src/linuxfibel is not relocateable for package linuxfibel_basis-0.6-0 |
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:
root@sonne> rpm -U --badreloc --relocate /usr/share/doc/linuxfibel=/usr/local/httpd/htdocs linuxfibel_basis-0.6-0.i386.rpm |
Zum Entfernen von Paketen dient die Option -e:
root@sonne> rpm -e linuxfibel_basis Fehler: Das Entfernen dieser Pakete würde Paket-Abhängigkeiten missachten: linuxfibel_basis wird von linuxfibel_kap10-0.6-0 gebraucht linuxfibel_basis wird von linuxfibel_kap1-0.6-0 gebraucht ... |
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.
Rpm-Pakete selbstgebaut |
Die 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
/usr/src/packages/RPMS
/usr/src/packages/SOURCES
/usr/src/packages/SPECS
/usr/src/packages/SRPMS
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«:
# Auszug aus /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):
user@sonne> vi ~/.rpmmacros %_topdir /home/user/myrpms user@sonne> mkdir -p ~/myrpms/{RPMS,SOURCES,SPECS,SRPMS} |
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«.
user@sonne> rpm --showrc | egrep '_rpmdir|_sourcedir|_specdir|_srcrpmdir' RPM_SOURCE_DIR="%{u2p:%{_sourcedir}}" RPM_SOURCE_DIR="%{_sourcedir}" -14: _rpmdir %{_topdir}/RPMS -14: _sourcedir %{_topdir}/SOURCES -14: _specdir %{_topdir}/SPECS -14: _srcrpmdir %{_topdir}/SRPMS |
Für die nachfolgende Ausführung gehen wir von oben skizzierter Verzeichnisstruktur eines SuSE-Linux aus.
Die 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äambel enthält allgemeine Informationen zum RPM-Paket und zum Bau. Jeder Eintrag besitzt die Form:
<Name> : <Beschreibung> |
wobei folgende Namen (»Tags«) möglich sind:
Buildroot
Copyright
Conflicts
Distribution
Group
Name
Packager
Patch
Prefix
Provides
Release
Requires
Source
Summary
Url
Vendor
Version
Der entsprechende Abschnitt aus der SPEC-Datei zum Linuxfibel-RPM-Paket sieht wie folgt aus:
|
Eine aussagekräftige Beschreibung zum Inhalt des Pakets ermöglicht die Sektion »description«. Der Text kann auf beliebig viele Zeilen ausgedehnt werden.
%description Die Linuxfibel ist ein distributionsunabhängiges Lehrbuch und Referenz zu Themen rund um Linux. |
Hier 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.
%define INSTALL_DIR /usr/share/doc/linuxfibel %prep rm -rf %{name}-%{version}.%{release} mkdir %{name}-%{version}.%{release} cd %{name}-%{version}.%{release} mkdir -p ./%{INSTALL_DIR} tar xzvf ../../SOURCES/%{name}-%{version}.%{release}.tgz -C ./%{INSTALL_DIR} |
Im 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.
Beinhaltet Informationen über die wesentlichen Änderungen der enthaltenen Software.
RPM entsorgt die »Überreste« der Installation stets selbst, mit der Ausnahme der Verwendung eines buildroot-Verzeichnisses. Ein solches sollte im clean-Eintrag entfernt werden.
%clean rm -r %{buildroot} |
Hier 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:
%attr (644, root, root) bla.txt |
Anstelle des Wertes kann ein Minus verwendet werden (-, root, root), um den aktuellen Wert beizubehalten.
%config[(missingok|noreplace)]
%defattr
%dir
%doc
%docdir
%ghost
%license
%readme
%verify
Die angegebenen Attribute einer Datei werden bei einer Überprüfung berücksichtigt
%verify (md5, owner, group, size) bla.txt |
Die Liste der einzufügenden Dateien kann auch [teilweise] in einer separaten Datei stehen. Diese wird wie folgt eingebunden:
%files -f Datei_mit_Liste |
Die 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.
%post cd %{INSTALL_DIR} %{INSTALL_DIR}/print_version.sh |
%postun cd %{INSTALL_DIR} test -d images && rm -r images rmdir %{INSTALL_DIR} |
Die 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.
%preun cd %{INSTALL_DIR} test -d printversion && rm -r printversion |
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.
Erzeugt wird ein RPM-Paket mit Hilfe des Kommandos rpm selbst:
rpm -bStadium [Optionen] SPEC-Datei [SPEC-Datei] |
Die mit Stadium bezeichneten Optionen steuern den Umfang des Paketbaus:
p | Ausführen der %prep-Sektion |
c | Ausführen der %prep- und %build-Sektion |
i | Ausführen der %prep-, %build- und %install-Sektion |
b | Ausführen der %prep-, %build- und %install-Sektion; Erzeugen des Binary-Pakets |
a | Wie b; zusätzlich wird ein Quell-RPM-Paket gebaut |
l | Test der %files-Liste (Existenz der Dateien, Überprüfung benötigter und bereit gestellter Bibliotheken) |
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
--clean
--rmsource
--test
--sign
--target Plattform
--buildroot Verzeichnis
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:
root@sonne> cd /usr/src/packages/SPECS; ls Linuxfibel.spec root@sonne> rpm -bb --target noarch Linuxfibel.spec Erzeuge Zielplattformen: noarch Paket wird erzeugt für Zielplattform noarch. Ausführung(%prep): /bin/sh -e /var/tmp/rpm-tmp.38531 + umask 022 + cd /usr/src/packages/BUILD + rm -rf linuxfibel-0.8.3 + mkdir linuxfibel-0.8.3 + cd linuxfibel-0.8.3 + mkdir -p /usr/share/doc/linuxfibel + tar xzvf /usr/src/packages/SOURCES/linuxfibel-0.8.3.tar.gz -C /usr/share/doc/linuxfibel access.htm allekapitel.htm ... xsteuerung.htm + exit 0 Verarbeitung der Dateien: linuxfibel-0.8-3 Suche Provides: (benutze /usr/lib/rpm/find-provides)... Suche Requires: (benutze /usr/lib/rpm/find-requires)... Provides: Linux Basiswissen PreReq: /bin/sh Geschrieben: /usr/src/packages/RPMS/noarch/linuxfibel-0.8-3.noarch.rpm Ausführung(%clean): /bin/sh -e /var/tmp/rpm-tmp.85181 + umask 022 + cd /usr/src/packages/BUILD + rm -rf /usr/share/doc/linuxfibel + exit 0 |
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).
Patch-Rpm |
Wä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.
user@sonne> man rpm ... --basedon Show what packages a patch-rpm is based on. A patch-rpm can only be installed if one of the pack ages it is based on is installed. ... |
Wie 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:
user@sonne> rpm -qp --basedon tk-8.4-64.i586.patch.rpm tk = 8.4-48 tk = 8.4-51 tk = 8.4-59 |
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:
root@sonne> rpm -i tk-8.4-64.i586.patch.rpm |
Ob ein Rpm-Paket gepatcht ist, erfahren Sie mit Hilfe der Option -P bzw. --patches, die alle ersetzten Dateien auflistet:
root@sonne> rpm -i tk-8.4-64.i586.patch.rpm |
user@sonne> rpm -ql --patches tk-8.4-48.i586.rpm root@sonne> rpm -i tk-8.4-64.i586.patch.rpm user@sonne> rpm -ql --patches tk-8.4-48.i586.rpm /usr/lib/libtk8.4.so |
user@sonne> cat linuxfibel.patch.spec # # spec file for linuxfibel.rpm # Vendor: Saxonia Systems AG Distribution: Gnu Linux Name: linuxfibel Version: __NEW_VERSION__ Release: __NEW_RELEASE__ Packager: linuxfibel@gmx.de Copyright: GPL Summary: Installiert das Linuxfibel Paket Group: Linux/Dokumentation Provides: linuxfibel Source: linuxfibel-%{version}-%{release}.tgz BuildRoot: /tmp/linuxfibel-%{version}.%{release}-root Patches: Linuxfibel = __INSTALLED_VERSION__ %description Die Linuxfibel ist ein distributionsunabhängiges Lehrbuch und Referenz zu Themen rund um Linux. Distribution: Gnu-Linux (i386) ##################################################################### %define INSTALL_DIR /usr/share/doc/linuxfibel ##################################################################### %prep rm -rf %{name}-%{version}.%{release} mkdir %{name}-%{version}.%{release} cd %{name}-%{version}.%{release} mkdir -p ./%{INSTALL_DIR} tar xzvf ../../SOURCES/%{name}-%{version}-%{release}.tgz -C ./%{INSTALL_DIR} ##################################################################### %install cd %{name}-%{version}.%{release} rm -f %{buildroot} ln -s `pwd` %{buildroot} ##################################################################### %clean rm -r %{buildroot} ##################################################################### %files %dir %{INSTALL_DIR} |
Deb-Pakete |
Gä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
dpkg-deb
dselect
apt-get
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
i - Install
r - Remove
p - Purge
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
half-configured, half-installed
installed/not-installed
unpacked
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.
Ebenso 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:
user@sonne> dpkg -l Desired=Unknown/Install/Remove/Purge/Hold | Status=Not/Installed/Config-files/Unpacked/Failed-config/Half-installed |/ Err?=(none)/Hold/Reinst-required/X=both-problems (Status,Err:uppercase=bad) ||/ Name Version Description +++-=============-===========-==================================================== ii adduser 3.11.1 Add users and groups to the system. ii ae 962-26 Anthony's Editor -- a tiny full-screen editor ii anacron 2.1-5.1 a cron-like program that doesn't go by time ii apt 0.3.19 Advanced front-end for dpkg ii asclassic 1.1b-12 A light window manager with the NEXTSTEP look and feel ii at 3.1.8-10 Delayed job execution and batch processing ii autoclass 3.3.2-2 automatic classification or clustering ii balsa 0.6.0-1.1 GNOME email client ii base-config 0.32 Debian base configuration ii base-files 2.2.0 Debian base system miscellaneous files ii base-passwd 3.1.7 Debian Base System Password/Group Files ii bash 2.03-6 The GNU Bourne Again SHell ii bc 1.05a-11 The GNU bc arbitrary precision calculator language ... |
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:
user@sonne> dpkg -l '??' Desired=Unknown/Install/Remove/Purge/Hold | Status=Not/Installed/Config-files/Unpacked/Failed-config/Half-installed |/ Err?=(none)/Hold/Reinst-required/X=both-problems (Status,Err:uppercase=bad) ||/ Name Version Description +++-=============-===========-==================================================== ii ae 962-26 Anthony's Editor -- a tiny full-screen editor pn af <none> (no description available) pn an <none> (no description available) ii at 3.1.8-10 Delayed job execution and batch processing pn bb <none> (no description available) ii bc 1.05a-11 The GNU bc arbitrary precision calculator language ... |
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:
user@sonne> dpkg -s xterm Package: xterm Status: install ok installed Priority: optional Section: x11 Installed-Size: 580 Maintainer: Branden Robinson <branden@debian.org> Source: xfree86-1 Version: 3.3.6-10 Replaces: xbase (<< 3.3.2.3a-2) Provides: x-terminal-emulator Depends: libc6 (>= 2.1.2), libncurses5, xlib6g (>= 3.3.6-4) Conflicts: xbase (<< 3.3.2.3a-2) Conffiles: /etc/X11/Xresources/xterm Description: X terminal emulator xterm is a terminal emulator for the X Window System. It provides DEC VT102 and Tektronix 4014 compatible terminals for programs that cannot use the window system directly. This version implements ISO/ANSI colors and most of the control sequences used by DEC VT220 terminals. |
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:
user@sonne> dpkg --info xterm_4.2.1-3_i386.deb new debian package, version 2.0. size 488764 bytes: control archive= 4039 bytes. 91 bytes, 3 lines conffiles 734 bytes, 17 lines control 1052 bytes, 16 lines md5sums 7914 bytes, 229 lines * postinst #!/bin/sh 147 bytes, 5 lines * postrm #!/bin/sh 7276 bytes, 218 lines * prerm #!/bin/sh Package: xterm Version: 4.2.1-3 Section: x11 Priority: optional Architecture: i386 Depends: debconf (>> 0.5), libc6 (>= 2.2.4-4), libfreetype6, libncurses5 (>= 5.2.20020112a-1), libxaw7 (>> 4.1.0), xlibs (>> 4.1.0) Conflicts: xbase (<< 3.3.2.3a-2), suidmanager (<< 0.50) Replaces: xbase (<< 3.3.2.3a-2) Provides: x-terminal-emulator Installed-Size: 900 Maintainer: Branden Robinson Source: xfree86 Description: X terminal emulator xterm is a terminal emulator for the X Window System. It provides DEC VT102 and Tektronix 4014 compatible terminals for programs that cannot use the window system directly. This version implements ISO/ANSI colors and most of the control sequences used by DEC VT220 terminals. |
Die Liste der von einem Paket bereit gestellten Dateien erhalten Sie mittels dpgk -L Paketname:
user@sonne> dpkg -L xterm /. /usr /usr/share /usr/share/doc /usr/share/doc/xterm /usr/share/doc/xterm/copyright /usr/share/doc/xterm/README.Debian /usr/share/doc/xterm/changelog.Debian.gz /usr/share/doc/xterm/xterm.faq.html /usr/share/doc/xterm/termcap.gz /usr/share/doc/xterm/ctlseqs.ms.gz |
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:
user@sonne> dpkg -S 'bin/*term' eterm: /usr/bin/Eterm gnome-terminal: /usr/bin/gnome-terminal rxvt: /usr/X11R6/bin/rxvt-xterm hanterm: /usr/X11R6/bin/hanterm kterm: /usr/X11R6/bin/kterm util-linux: /usr/bin/setterm xterm: /usr/X11R6/bin/xterm |
Die 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:
user@sonne> apt-cache showpkg xterm Package: xterm Versions: 4.2.1-3(/var/lib/dpkg/status) Reverse Depends: xfree86-common,xterm x-window-system,xterm pgi,xterm seyon,xterm gkdebconf,xterm tn5250,xterm debroster,xterm user-mode-linux,xterm seaview,xterm ddd,xterm lincvs,xterm texdoctk,xterm tk-brief,xterm Dependencies: 4.2.1-3 - debconf (4 0.5) libc6 (2 2.2.4-4) libfreetype6 (0 (null)) libncurses5 (2 5.2.20020112a-1) libxaw7 (4 4.1.0) xlibs (4 4.1.0) xbase (3 3.3.2.3a-2) suidmanager (3 0.50) xbase (3 3.3.2.3a-2) Provides: 4.2.1-3 - x-terminal-emulator Reverse Provides: |
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.
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:
user@sonne> cd / user@sonne> md5sum -c /var/lib/dpkg/info/xterm.md5sums md5sum: MD5 check failed for 'usr/X11R6/bin/xterm' |
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.
...noch paar einführende Worte finden...
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.
dpkg -i Paketname dpkg -i [-R] Verzeichnis |
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:
user@sonne> find /cdrom/ -name 'ddd*deb' /cdrom/debian/pool/main/d/ddd/ddd_3.3.1-14_i386.deb user@sonne> dpkg -i /cdrom/debian/pool/main/d/ddd/ddd_3.3.1-14_i386.deb Selecting previously deselected package ddd. (Reading database ... 29164 files and directories currently installed.) Unpacking ddd (from .../d/ddd/ddd_3.3.1-14_i386.deb) ... Setting up ddd (3.3.1-14) ... |
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.
apt-get install Paketname |
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.
user@sonne> pwd /var/lib/dpkg/info root@sonne> apt-get install ddd Reading Package Lists... Building Dependency Tree... The following NEW packages will be installed: ddd 0 packages upgraded, 1 newly installed, 0 to remove and 0 not upgraded. Need to get 0B/1573kB of archives. After unpacking 4455kB will be used. Media Change: Please insert the disc labeled 'Debian GNU/Linux 3.0-testing (woody) , disk 3 _2002-08-14/21:54_' in the drive '/cdrom/' and press enter Selecting previously deselected package ddd. (Reading database ... 29165 files and directories currently installed.) Unpacking ddd (from .../d/ddd/ddd_3.3.1-14_i386.deb) ... Setting up ddd (3.3.1-14) ... |
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.
dpkg --unpack Paketname dpkg --unpack [-R] Verzeichnis |
Die Option --unpack arbeitet wie -i mit dem einzigen Unterschied, dass der abschließende Schritt der Konfiguration des neuen Pakets ausgelassen wird.
user@sonne> dpkg --unpack /cdrom/debian/pool/main/d/ddd/ddd_3.3.1-14_i386.deb Selecting previously deselected package ddd. (Reading database ... 29164 files and directories currently installed.) Unpacking ddd (from .../d/ddd/ddd_3.3.1-14_i386.deb) ... Desired=Unknown/Install/Remove/Purge/Hold | Status=Not/Installed/Config-files/Unpacked/Failed-config/Half-installed |/ Err?=(none)/Hold/Reinst-required/X=both-problems (Status,Err: uppercase=bad) ||/ Name Version Description +++-=====================-=====================- ========================================================== iU ddd 3.3.1-14 The Data Display Debugger, a graphical debugger frontend. |
Eine nachträgliche Konfiguration ist möglich und wird im nachfolgenden Abschnitt beschrieben.
Erfolgte eine Installation ohne anschließender Konfiguration eines Pakets, können Sie letzteren Schritt nachholen, indem Sie »dpkg --configure Paketname« ausführen:
user@sonne> dpkg --configure ddd Setting up ddd (3.3.1-14) ... user@sonne> dpkg --list ddd Desired=Unknown/Install/Remove/Purge/Hold | Status=Not/Installed/Config-files/Unpacked/Failed-config/Half-installed |/ Err?=(none)/Hold/Reinst-required/X=both-problems (Status,Err: uppercase=bad) ||/ Name Version Description +++-=====================-=====================- ========================================================== ii ddd 3.3.1-14 The Data Display Debugger, a graphical debugger frontend. |
Fehlerhafte Installationen identifizieren Sie anhand der Statusspalten beim Listing eines Pakets:
user@sonne> dpkg -l ddd Desired=Unknown/Install/Remove/Purge/Hold | Status=Not/Installed/Config-files/Unpacked/Failed-config/Half-installed |/ Err?=(none)/Hold/Reinst-required/X=both-problems (Status,Err: uppercase=bad) ||/ Name Version Description +++-=====================-=====================- ========================================================== iHR ddd 3.3.1-14 |
»H« weist auch eine unvollständige Installation hin. Mit »R« wird eine erneute Installation empfohlen, um das Problem zu beheben:
user@sonne> apt-get install ddd Reading Package Lists... Building Dependency Tree... 1 packages upgraded, 0 newly installed, 0 to remove and 0 not upgraded. 1 packages not fully installed or removed. Need to get 0B/1573kB of archives. After unpacking 4455kB will be used. (Reading database ... dpkg: serious warning: files list file for package `ddd' missing, assuming package has no files currently installed. 29164 files and directories currently installed.) Preparing to replace ddd 1:3.3.1-14 (using .../d/ddd/ddd_3.3.1-14_i386.deb) ... Unpacking replacement ddd ... Setting up ddd (3.3.1-14) ... |
Die Statusspalten sollten sich bei Erfolg folgendermaßen präsentieren:
user@sonne> dpkg -l ddd Desired=Unknown/Install/Remove/Purge/Hold | Status=Not/Installed/Config-files/Unpacked/Failed-config/Half-installed |/ Err?=(none)/Hold/Reinst-required/X=both-problems (Status,Err: uppercase=bad) ||/ Name Version Description +++-=====================-=====================- ========================================================== ii ddd 3.3.1-14 The Data Display Debugger, a graphical debugger frontend. |
Auch 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.
root@sonne> dpkg -r ddd (Reading database ... 29235 files and directories currently installed.) Removing ddd ... user@sonne> dpkg -l ddd Desired=Unknown/Install/Remove/Purge/Hold | Status=Not/Installed/Config-files/Unpacked/Failed-config/Half-installed |/ Err?=(none)/Hold/Reinst-required/X=both-problems (Status,Err: uppercase=bad) ||/ Name Version Description +++-=====================-=====================- ========================================================== rc ddd 3.3.1-14 The Data Display Debugger, a graphical debugger frontend. |
root@sonne> apt-get remove ddd Reading Package Lists... Building Dependency Tree... The following packages will be REMOVED: ddd 0 packages upgraded, 0 newly installed, 1 to remove and 0 not upgraded. Need to get 0B of archives. After unpacking 4455kB will be freed. Do you want to continue? [Y/n] Y (Reading database ... 29235 files and directories currently installed.) Removing ddd ... user@sonne> dpkg -l ddd Desired=Unknown/Install/Remove/Purge/Hold | Status=Not/Installed/Config-files/Unpacked/Failed-config/Half-installed |/ Err?=(none)/Hold/Reinst-required/X=both-problems (Status,Err: uppercase=bad) ||/ Name Version Description +++-=====================-=====================- ========================================================== rc ddd 3.3.1-14 The Data Display Debugger, a graphical debugger frontend. |
root@sonne> dpkg -P ddd (Reading database ... 29235 files and directories currently installed.) Removing ddd ... Purging configuration files for ddd ... user@sonne> dpkg -l ddd Desired=Unknown/Install/Remove/Purge/Hold | Status=Not/Installed/Config-files/Unpacked/Failed-config/Half-installed |/ Err?=(none)/Hold/Reinst-required/X=both-problems (Status,Err: uppercase=bad) ||/ Name Version Description +++-=====================-=====================- ========================================================== pn ddd (no description available) |
root@sonne> apt-get --purge remove ddd Reading Package Lists... Building Dependency Tree... The following packages will be REMOVED: ddd* 0 packages upgraded, 0 newly installed, 1 to remove and 0 not upgraded. Need to get 0B of archives. After unpacking 4455kB will be freed. Do you want to continue? [Y/n] Y (Reading database ... 29235 files and directories currently installed.) Removing ddd ... Purging configuration files for ddd ... user@sonne> dpkg -l ddd Desired=Unknown/Install/Remove/Purge/Hold | Status=Not/Installed/Config-files/Unpacked/Failed-config/Half-installed |/ Err?=(none)/Hold/Reinst-required/X=both-problems (Status,Err: uppercase=bad) ||/ Name Version Description +++-=====================-=====================- ========================================================== pn ddd (no description available) |
Haben 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«:
user@sonne> dpkg -l ddd Desired=Unknown/Install/Remove/Purge/Hold | Status=Not/Installed/Config-files/Unpacked/Failed-config/Half-installed |/ Err?=(none)/Hold/Reinst-required/X=both-problems (Status,Err: uppercase=bad) ||/ Name Version Description +++-=====================-=====================- ========================================================== rc ddd 3.3.1-14 The Data Display Debugger, a graphical debugger frontend. root@sonne> apt-get --purge remove ddd Reading Package Lists... Building Dependency Tree... Package ddd is not installed, so not removed 0 packages upgraded, 0 newly installed, 0 to remove and 0 not upgraded. root@sonne> dpkg -P ddd (Reading database ... 29165 files and directories currently installed.) Removing ddd ... Purging configuration files for ddd ... |
Deb-Pakete selbstgebaut |
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.
Die Namenswahl von (offiziellen) Debian-Paketen ist fest vorgegeben:
<Paketname>_<Versionsnummer des Programmes>-<Releasenummer>_<Architektur>.deb |
Die Releasenummer ist gleichbedeutend mit der Versionsnummer der Paketerstellung.
Eines 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:
user@sonne> ar tvf xterm_4.2.1-3_i386.deb rw-r--r-- 0/0 4 Oct 19 23:38 2002 debian-binary rw-r--r-- 0/0 4039 Oct 19 23:38 2002 control.tar.gz rw-r--r-- 0/0 484532 Oct 19 23:38 2002 data.tar.gz |
Das Entpacken der Dateien erolgt erfolgt analog zur Option des tar-Kommandos mit x:
user@sonne> ar xf xterm_4.2.1-3_i386.deb |
debian-binary
user@sonne> cat debian-binary 2.0 |
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
user@sonne> tar tzvf control.tar.gz
drwxr-xr-x root/root 0 2002-10-19 23:37:13 ./ -rw-r--r-- root/root 734 2002-10-19 23:37:09 ./control -rwxr-xr-x root/root 7276 2002-10-19 23:36:18 ./prerm -rw-r--r-- root/root 91 2002-10-19 22:22:51 ./conffiles -rw-r--r-- root/root 1052 2002-10-19 23:37:13 ./md5sums -rwxr-xr-x root/root 7914 2002-10-19 23:36:18 ./postinst -rwxr-xr-x root/root 147 2002-10-19 23:36:18 ./postrm |
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:
user@sonne> cat control
Package: xterm Version: 4.2.1-3 Section: x11 Priority: optional Architecture: i386 Depends: debconf (>> 0.5), libc6 (>= 2.2.4-4), libfreetype6, \ libncurses5 (>= 5.2.20020112a-1), libxaw7 (>> 4.1.0), xlibs (>> 4.1.0) Conflicts: xbase (<< 3.3.2.3a-2), suidmanager (<< 0.50) Replaces: xbase (<< 3.3.2.3a-2) Provides: x-terminal-emulator Installed-Size: 900 Maintainer: Branden Robinson <branden@debian.org> Source: xfree86 Description: X terminal emulator xterm is a terminal emulator for the X Window System. It provides DEC VT102 and Tektronix 4014 compatible terminals for programs that cannot use the window system directly. This version implements ISO/ANSI colors and most of the control sequences used by DEC VT220 terminals. |
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:
preinst | install, upgrade |
postinst | configure |
prerm | remove, upgrade |
postrm | remove, purge |
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:
user@sonne> cat conffiles /etc/X11/app-defaults/UXTerm /etc/X11/app-defaults/XTerm /etc/X11/app-defaults/XTerm-color |
Die Unversehrheit der Dateien in einem Paket kann anhand des Inhalts einer Datei md5sums verifiziert werden, insofern die Paketbauer diese sinnvolle Eigenschaft vorgesehen hatten:
user@sonne> cat md5sums d672bbf649879f0ce1f340b12f9f8283 usr/lib/menu/xterm 1f68f7ccdb684fb957d7dd983e24e853 usr/X11R6/bin/xterm ea8870cc936d434239667b3ae5a969bb usr/X11R6/bin/uxterm 44bb39c5d838a6f062b3735562d459d3 usr/X11R6/man/man1/xterm.1x.gz 096965faecdbdf21e26a667d86a5b415 usr/X11R6/man/man1/uxterm.1x.gz 89fc7c793984ab7c1d8288ceb0dc9f14 usr/share/doc/xterm/xterm.faq.html 526f04b3821954928cde267aeb3306f2 usr/share/doc/xterm/ctlseqs.txt.gz 5ae55d1ac3656abfa4def63d08154852 usr/share/doc/xterm/xterm.faq.text.gz 792df42bff304318c856fd70517c425c usr/share/doc/xterm/xterm.termcap.gz 3f9346aec8a5fcc6f61d35e0560717fe usr/share/doc/xterm/xterm.log.html b6817b9e8bf67218513e02cfec51385a usr/share/doc/xterm/README.Debian 05469648defd7feef538795654c26b19 usr/share/doc/xterm/xterm.terminfo.gz 2f42d779fe32dc12631e1e5d9a3960c2 usr/share/doc/xterm/copyright 9e3d633a5fb22f4f42b373dd9fc5f45a usr/share/doc/xterm/ctlseqs.ps.gz d18d22063d3c60f1cbf27b8d06015102 usr/share/doc/xterm/changelog.Debian.gz b41453c1f2d3fec3baeb1209fe33f102 usr/share/doc-base/xterm-faq1 |
data.tar.gz
Dieses Archiv enthält die eigentlichen Paketdateien (Programme, Dokumentationen, Konfigurationsdateien...).
Nach den allgemein gehaltenen Vorbetrachtungen vollführen wir den Schritt zum Debian-Paket anhand des konkreten Beispiels der Linuxfibel.
Zunä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«:
root@sonne> mkdir -p /usr/src/deb/linuxfibel # Die Arbeit als Root ist u.U. gefährlich! root@sonne> chown user:users /usr/src/deb/linuxfibel user@sonne> cd /usr/src/deb/linuxfibel user@sonne> mkdir DEBIAN user@sonne> chmod 755 DEBIAN |
In das Unterverzeichnis DEBIAN gelangen später die Beschreibungsdateien und (De)Installations-Skripte.
In 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:
user@sonne> (cd /; tar cf - /usr/doc/share/linuxfibel) | tar xvf - |
Sä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
user@sonne> cat DEBIAN/debian-binary 2.0 |
control
Der im Beispiel verwendete Inhalt der Datei »control« umfasst die minimal erforderlichen Einträge.
user@sonne> cat DEBIAN/control Package: linuxfibel Version: 0.8-2 Section: base Priority: optional Architecture: all Maintainer: Thomas Ermer <thomas.ermer@saxsys.de>, Michael Meyer <michael.meyer@saxsys.de> Description: Die Linuxfibel Die Linuxfibel ist ein distributionsunabhängiges Lehrbuch und Referenz zu Themen rund um Linux. |
Wichtige Einträge darüber hinaus sind:
Depends
Conflicts
Replaces
Provides
Installed-Size
md5-Prüfsummen
Wir statten unser Paket mit MD5-Prüfsummen über jede der Dateien aus:
user@sonne> find /usr/share/linuxfibel -type f -exec md5sum {} \; > DEBIAN/md5sum |
Hierfü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:
user@sonne> pwd /usr/src/deb/linuxfibel user@sonne> cd .. root@sonne> dpkg-deb --build linuxfibel dpkg-deb: building package `linuxfibel' in `linuxfibel.deb'. |
Das fertige Paket liegt als »linuxfibel.deb« vor. Wir prüfen dessen Kontrolldatei:
user@sonne> dpkg --info linuxfibel.deb new debian package, version 2.0. size 7258184 bytes: control archive= 345 bytes. 303 bytes, 8 lines control Package: linuxfibel Version: 0.8-2 Section: base Priority: optional Architecture: all Maintainer: Thomas Ermer <thomas.ermer@saxsys.de>, Michael Meyer <michael.meyer@saxsys.de> Description: Die Linuxfibel Die Linuxfibel ist ein distributionsunabhängiges Lehrbuch und Referenz zu Themen rund um Linux. |
Um der Namenskonvention für Debian-Pakete zu entsprechen, ist das Paket noch umzubenennen:
root@sonne> mv linuxfibel.deb linuxfibel_0.8-2_1_i386.deb |
Alien |
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:
Zum Lesen/Erzeugen eines Rpm-Pakets: | rpm |
Zum Lesen/Erzeugen eines Tgz-Pakets: | tar |
Zum Lesen/Erzeugen eines Deb-Pakets: | debmake, dpkg-dev, dpks, make und gcc |
Auch 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!
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:
--to-tgz | Erzeugen des Tgz-Formats |
--to-rpm | Erzeugen des Rpm-Formats |
--to-deb | Erzeugen des Deb-Formats (Voreinstellung) |
--to-slp | Erzeugen des Slp-Formats |
Das nachfolgende Beispiel wandelt das Linuxfibel-Basis-RPM-Paket in das Tgz-Format:
user@sonne> alien --to-tgz linuxfibel_basis-0.6-0.i386.rpm Warning: alien is not running as root! Ownerships of files in the generated packages will probably be messed up. linuxfibel_basis-0.6.tgz generated |
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:
root@sonne> alien --to-rpm
linuxfibel_basis-0.6.tgz linuxfibel_basis-0.6.2.noarch.rpm generated |
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.
Bibliotheken |
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:
user@sonne> ./MyProgram ld.so: MyProg: fatal: libMylib.so: can't open file |
Ein 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...
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:
user@sonne> strings /lib/cat | head
-1 /lib/ld-linux.so.2 |
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.
Natü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:
user@sonne> ldd /bin/ls libtermcap.so.2 => /lib/libtermcap.so.2 (0x40024000) librt.so.1 => /lib/librt.so.1 (0x40028000) libc.so.6 => /lib/libc.so.6 (0x4003a000) libpthread.so.0 => /lib/libpthread.so.0 (0x40167000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000) user@sonne> ldd -v /lib/libc.so.6 /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000) Version information: /lib/libc.so.6: ld-linux.so.2 (GLIBC_2.1.1) => /lib/ld-linux.so.2 ld-linux.so.2 (GLIBC_2.1) => /lib/ld-linux.so.2 ld-linux.so.2 (GLIBC_2.2) => /lib/ld-linux.so.2 ld-linux.so.2 (GLIBC_2.0) => /lib/ld-linux.so.2 |
Die im Beispiel angewandte Option -v gibt einige erweitere Informationen preis.
Wie 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:
root@sonne> 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:
root@sonne> vi /etc/ld.so.conf /usr/X11R6/lib /usr/local/lib |
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.