Aus Linux-Magazin 02/2006

Debian-Pakete untersuchen und erzeugen

© photocase.com

Wer seine Geschenke letztes Jahr zu klein fand, der schnürt sich einfach sein eigenes Paket nach dem Debian-Standard. Mit wachsender Anzahl Debian-basierter Distributionen steigt auch die Bedeutung des als besonders komfortabel geltenden Formats.

Ob auf dem Desktop-PC oder dem stark beanspruchten Serversystem: Bei Administratoren jeder Couleur hat das Debian-Paketmanagement DPKG einen guten Ruf. Denn auch ohne intime Kenntnis des Formats installieren, aktualisieren und entfernen sie damit Programme inklusive komplexer Abhängigkeiten mit nur einem »apt-get«-Aufruf.

Doch nicht für jeden Bedarf findet sich ein fertiges Deb-Archiv. Triviale Pakete, wie sie beispielsweise Checkinstall erzeugt, helfen zwar später bei der Deinstallation, doch wer Abhängigkeiten berücksichtigen oder eigene Pakete auf mehreren Rechnern installieren möchte, benötigt korrekt gebaute Deb-Dateien.

Aufbau

Ein Debian-Paket ist zunächst nichts anderes als ein AR-Archiv. Dieses Archivierungssystem gehört zu den Binutils und damit zu jeder Linux-Installation. Dass Debian dieses Format verwendet, ermöglicht den Zugriff auf die Paketdateien mit praktisch jedem Unix-System. Das Archiv enthält mindestens drei Dateien (siehe Abbildung 1):

  • »debian-binary«
  • »control.tar.gz«
  • »data.tar.gz«

Das Paketverwaltungssystem stellt zunächst fest, ob die Datei »debian-binary« existiert, bevor es das Paket bearbeitet. Obwohl sie bislang lediglich aus einer Zeile besteht, die die Versionsnummer des Deb-Formats angibt, ist »debian-binary« obligatorisch. Seit 1995 hat sie sich in puncto Inhalt und Aufbau nicht mehr verändert und lautet stets »2.0«.

Bei »control.tar.gz« handelt es sich um ein gewöhnliches mit Gzip komprimiertes Tar-Archiv. Aus den darin enthaltenen Metadaten bezieht das Paketwerkzeug DPKG alle über das Paket benötigten Informationen. Im Archiv sind weder Unterverzeichnisse noch Links oder andere Spezialdateien, sondern ausschließlich herkömmliche Dateien erlaubt.

Abbildung 1: Bei einem Debian-Paket handelt es sich um ein AR-Archiv, das fest definierte Dateien enthält. Darin stehen neben den komprimierten Programmdateien selbst auch alle Paketinformationen.

Abbildung 1: Bei einem Debian-Paket handelt es sich um ein AR-Archiv, das fest definierte Dateien enthält. Darin stehen neben den komprimierten Programmdateien selbst auch alle Paketinformationen.

Als einzigen zwingenden Eintrag enthält es eine Datei namens »control« in einem Debian-eigenen Format (siehe Kasten “Control-Format”). Aus ihrem Inhalt entsteht unter anderem der zum jeweiligen Paket gehörige Eintrag in der Liste verfügbarer Software in der systemweiten Datei »Packages«.

Auch alle anderen Informationen, die die Paketverwaltung vor der Installation benötigt, stehen in der Datei »control«. Die vorgeschriebenen Felder heißen »Package«, »Version«, »Description« und »Maintainer«. Sie geben Auskunft über Namen und Version der enthaltenen Software sowie eine Beschreibung. Das Feld für den Paketbetreuer enthält dessen Namen und E-Mail-Adresse. Darüber hinaus sind neben »Architecture«, »Priority« und »Section« noch »Depends« und andere Informationen über Abhängigkeiten von oder Konflikte mit weiteren Softwarepaketen üblich.

Eine Policy für alle

Das Format der einzelnen Felder beschreibt die Debian-Policy [1]. Dieses Dokument bezieht sich zwar speziell auf die Distribution Debian, gilt jedoch in puncto Paketbeschreibung für alle Debian-basierten Linux-Varianten. Optional enthält das Archiv »control.tar.gz« auch beispielsweise folgende Dateien:

  • »conffiles«: Führt Dateien auf, die DPKG als
    Konfigurationsdateien behandeln soll. Diese überschreibt es
    bei einem Upgrade nicht automatisch, es sei denn, sie sind ohnehin
    identisch.
  • »preinst«, »postinst«,
    »prerm« und »postrm«: Die so genannten
    Maintainer-Skripte sind ausführbare Dateien, die DPKG vor und
    nach der Installation beziehungsweise Deinstallation von Paketen
    aufruft. Sie eignen sich vor allem zum Registrieren und Entfernen
    systemweiter Einträge: Menüpunkte behandelt der Aufruf
    von »update-menus«, um Info-Dateien kümmert sich
    »install-info« und um Standardprogramme wie
    Texteditoren »update-alternatives«. Auch zum Erstellen
    System- oder Benutzer-abhängiger Konfigurationsdateien mit
    Debconf oder UCF dienen die Maintainer-Skripte. Ausführliche
    Informationen darüber gibt [2].
  • »config« und »templates«: Debconf
    verwendet diese Dateien, um während der Installation vom
    Benutzer Informationen zu erfragen. »config« ist eine
    ausführbare Datei, »templates« entspricht dem
    Control-Format.
  • »md5sums«: Eine Liste mit MD5-Prüfsummen der
    im Paket enthaltenen Dateien. Damit überprüft
    beispielsweise Debsums die Integrität eines installierten
    Pakets.
  • »shlibs«: Informationen über im Paket
    enthaltene Shared Libraries, aus deren
    Abhängigkeitsinformationen andere Pakete eigene Dependencies
    automatisch ableiten können [3].

Kopien aller im Archiv »control.tar.gz« enthaltenen Dateien speichert die Paketverwaltung bei der Installation unter »/var/lib/dpkg/info/ Paketname.Dateiname«. Einzige Ausnahme bildet der Inhalt der »control«-Datei: Er landet in der zentralen Paketdatenbank »/var/lib/dpkg/status«.

Bei »data.tar.gz« handelt es sich um ein weiteres komprimiertes Tar-Archiv. Es enthält die Programmdateien, DPKG entpackt seinen Inhalt bei der Installation in das Wurzelverzeichnis des Systems. Nur bei den mit einem »conffiles«-Eintrag als Konfigurationsdateien beschriebenen Inhalten gilt die weiter oben beschriebene Ausnahme.

Vor dem Entpacken trifft DPKG jedoch einige Vorsichtsmaßnahmen. So überprüft es, ob dabei bereits vorhandene Dateien überschrieben würden, und im Falle eines Upgrade legt es von jeder Datei der alten Paketversion eine Sicherheitskopie an, um damit den Vorgang im Falle eines Abbruchs rückgängig zu machen.

Eigene Erweiterungen

Entspricht ein fertiges Paket nicht den Ansprüchen, macht das Debian-Format es leicht, eigene Wünsche auch ohne Neukompilieren einzubinden. Eine Möglichkeit besteht im Anpassen der »control«-Datei. So verwenden beispielsweise die UDEB-Pakete des Debian-Installers eigene Control-Felder, um Informationen wie die Reihenfolge der Einträge im Installations-Hauptmenü zu definieren.

Wer einem Paket Dateien hinzufügen möchte, hängt diese ans Ende des AR-Archivs an oder gibt ihnen einen mit einem Unterstrich beginnenden Namen. In der Praxis greift derzeit jedoch ausschließlich das Programm »dpkg-sig« auf diese Möglichkeit zurück. Es fügt Paketen auf diese Weise eine besondere Signatur hinzu, um sie vor Manipulationen zu schützen.

Auch andere Metadaten gehören ins »control.tar.gz«-Archiv. Beispielsweise finden hier zusätzliche MD5-Prüfsummen oder alternative Konfigurationsdateien, die dem Benutzer bei der Installation via Debconf zur Wahl stehen, ihren Platz. Um ein fertiges Debian-Paket zu untersuchen oder zu verändern, reichen prinzipiell die auf jedem Unix-System verfügbaren Werkzeuge »ar«, »tar« und »gzip«. Doch spezialisierte Tools erleichtern den Umgang mit den Paketen.

Wie ein einfacher Wrapper um die häufigsten Aufrufe dieser drei Werkzeuge fungiert »dpkg-deb«. Es nimmt dem Benutzer vor allem die Eingabe der Dateinamen in den Archiven ab. Typische Aufrufe heißen »dpkg-deb –contents«, das dem Kommando »tar -tzf data.tar.gz« entspricht, oder »dpkg-deb –control« (»tar -xz control.tar.gz«). Eine komplette Liste der verfügbaren Optionen führt die Manpage von »dpkg-deb«.

Andere Werkzeuge machen die Kommandozeile beim Durchstöbern von Debian-Paketen gänzlich überflüssig. Wer auf der Konsole verweilen möchte, verwendet dazu den Curses-basierten Dateimanager Midnight Commander oder den Debview-Mode für Emacs. Ark für KDE und der Gnome-Archivmanager lesen Debian-Pakete ebenfalls. Beim Bearbeiten eines Deb-Archivs helfen diese Programme jedoch nicht. Dazu ist nach wie vor das Entpacken und erneute Zusammenfügen über »dpkg-deb –build« nötig.

Abbildung 2: Vom Quellcode- zum Binärpaket führen verschiedene Wege. Im Mittelpunkt steht das »rules«-Skript.

Abbildung 2: Vom Quellcode- zum Binärpaket führen verschiedene Wege. Im Mittelpunkt steht das »rules«-Skript.

Abbildung 3: Mehrere DPKG-Entwicklungswerkzeuge sind erforderlich, um aus einem Quellcode- ein Binärpaket zu erzeugen. Da sie auf von ihnen erzeugten Dateien aufbauen, ist die richtige Aufrufreihenfolge wichtig.

Abbildung 3: Mehrere DPKG-Entwicklungswerkzeuge sind erforderlich, um aus einem Quellcode- ein Binärpaket zu erzeugen. Da sie auf von ihnen erzeugten Dateien aufbauen, ist die richtige Aufrufreihenfolge wichtig.

Quellcode-Pakete

Neue Debian-Pakete entstehen üblicherweise aus Quellcode-Paketen. Andere Wege gehen beispielsweise die Programme »equivs«, »alien« und »checkinstall«. Ersteres erstellt Meta-Pakete mit einem leeren »data.tar.gz«-Archiv aus einer einzigen Konfigurationsdatei. »alien« konvertiert andere Paketformate wie RPM ins Debian-Format. »checkinstall« schnürt neben Debian- auch Pakete wie RPMs. Nachdem der Benutzer den Quelltext mit »make« kompiliert hat, erstellt es ein einfaches Paket, ohne Abhängigkeiten oder Konflikte zu berücksichtigen.

Wer also ein zuverlässiges Binärpaket benötigt, braucht zuvor ein korrektes Quellcode-Paket. In Aufbau und Struktur haben Quellcode- und Binärpakete wenig gemeinsam. So unterscheiden sich zum Nachteil der Benutzer auch die beiden Programme »dpkg-deb« und »dpkg-source« in puncto Code und Anwendung deutlich. Ein Quellcode-Paket enthält zwei oder drei einzelne Dateien:

  • Eine Datei im Control-Format mit der Endung ».dsc«.
    Sie liefert unter anderem die Namen der im Archiv vorhandenen
    Dateien und informiert damit über den Inhalt des
    Quellcode-Pakets.
  • Eine komprimierte Patch-Datei im Unified-Diff-Format mit der
    Endung ».diff.gz«. Sie ist optional und beschreibt die
    distributionsspezifischen Änderungen am Quellcode.
  • Ein komprimiertes Tar-Archiv mit der Endung
    ».orig.tar.gz«, das den Quelltext des Programms
    enthält. Im Regelfall handelt es sich dabei um den originalen
    Quellcode, die so genannte Upstream Source. Falls keine
    ».diff.gz«-Datei existiert, entfällt auch der
    Zusatz ».orig« im Archivnamen. Man spricht in diesem
    Fall von einem nativen Debian-Paket.

Existiert eine Patch-Datei, kommt sie beim Aufruf von »dpkg-source -x Dateiname.dsc« zum Einsatz. Dieser Befehl entpackt zunächst das Tar-Archiv und wendet das Patch anschließend an. Das entstandene Quellcode-Verzeichnis enthält nun ein Unterverzeichnis »debian«, in dem mindestens die folgenden Dateien liegen:

  • »rules«: Eine ausführbare Make-Datei, die alle
    Instruktionen zum Erstellen eines oder mehrerer binärer Pakete
    liefert.
  • »control«: Eine Datei im Control-Format, die
    über das Quellcode-Paket und alle aus ihm zu bauenden
    Binärpakete informiert. Sie liefert die meisten der
    später in den »control«-Dateien der
    Binärpakete erneut auftauchenden Daten. Eine Ausnahme bildet
    die Versionsnummer: Für sie zeichnet die Changelog-Datei
    verantwortlich.
  • »changelog«: Die Liste der Änderungen am Paket
    im Debian-eigenen Changelog-Format, wie es die Debian-Policy [1]
    beschreibt. Diese Datei definiert die Versionsnummer des
    Quellcode-Pakets und damit üblicherweise auch die der
    Binärpakete.

Die meisten Pakete enthalten im »debian«-Verzeichnis zusätzlich noch frei definierbare Dateien, auf die das Skript »rules« beim Kompilieren zurückgreift.

Listing 1a:
Rules-Skript

01 #!/usr/bin/make -f
01 
01 clean:
01   $(MAKE) clean
01   rm -f debian/files debian/substvars
01 
01 binary:
01   $(MAKE)
01   $(MAKE) install DESTDIR=$(CUR_DIR)/debian/tmp
01   dpkg-shlibdeps `find $(CUR_DIR)/debian/tmp/usr/bin`
01   dpkg-gencontrol
01   dpkg --build debian/tmp ..

Listing 1b:
Control-Datei

01 01 Source: foo
01 Maintainer: Frank Lichtenheld <djpig@debian.org>
01 
01 Package: foo
01 Architecture: any
01 Depends: ${shlibs:Depends}
01 Description: minimal example package

Vom Quellcode zum Binary

Gemäß der Debian-Paket-Policy führt der Weg vom Quellcode- zum Binärpaket ausschließlich über den Aufruf von »./debian/rules« mit der Angabe eines Target als Parameter. Das Verhalten eines Aufrufs ohne Zielnamen definiert die Policy nicht; er liefert deshalb im Allgemeinen kein vorhersehbares Ergebnis. Die einzigen festgelegten und wichtigsten Zielnamen lauten »clean« und »binary« sowie die zugehörigen Unterziele »binary-arch« und »binary-indep«.

»clean« versetzt den Quellcode in den Zustand zurück, den er nach dem Entpacken hatte. In den meisten Fällen geschieht dies über den dem Upstream-Makefile übergebenen Parameter »distclean« und das Entfernen temporärer Dateien und Verzeichnisse.

»binary« erstellt alle Binärpakete und erledigt die nötigen Vorarbeiten. Wie es das bewerkstelligt, bleibt dem Skript überlassen, üblicherweise benutzt es dazu »dpkg-deb«. Außerdem legt der Aufruf von »rules binary« eine Liste der erstellten Pakete in der Datei »debian/files« an, damit andere Werkzeuge die erzeugten Dateien weiterverwenden können, beispielsweise um sie in einem Archiv zusammenzufassen.

Den Umgang mit Quellcode-Paketen vereinfachen die Parameter »binary-arch«, der ausschließlich Architektur-spezifische Pakete baut, und »binary-indep«, der nur Architektur-unabhängige Pakete erstellt. Normalerweise handelt es sich bei »binary« um ein leeres Target, das von diesen beiden abhängt.

Wenn das Kommando »debian/rules binary« die Vorarbeiten geleistet hat, kann »dpkg-deb –build« ordnungsgemäß arbeiten. Es setzt ein Build-Verzeichnis voraus, aus dem es »data.tar.gz« erstellt. Das Build Directory muss wiederum ein Unterverzeichnis namens »DEBIAN« enthalten, das »dpkg-deb –build« zunächst im Archiv »control.tar.gz« sichert und anschließend löscht.

Das Build-Verzeichnis darf überall liegen, die DPKG-Programme gehen ohne weitere Angab#en vom Standard »debian/tmp« aus. Andere Tools suchen stattdessen nach »debian/ Paketname«. »dpkg-deb –build« selbst nimmt jedoch keine Änderungen an den Dateien vor, der Inhalt der Tar-Archive und die Meta-Information der »control«-Datei müssen deshalb zum Zeitpunkt des Programmstarts vorliegen.

Kontrolldaten

Um die Meta-Informationen kümmert sich das Programm »dpkg-gencontrol«, das die Informationen der Datei »debian/control« des Quellcode-Pakets um die aktuelle Versionsnummer ergänzt. Die extrahiert es mit »dpkg-parsechangelog« aus der Changelog-Datei.

»dpkg-gencontrol« ersetzt optional außerdem in der »control«-Datei enthaltene Variablen. Diese so genannten Substvars erfährt es entweder über Kommandozeilenparameter oder aus der Datei »debian/substvars«. Häufig kommt dieser Mechanismus beim Erstellen dynamischer Abhängigkeiten mit »dpkg-shlibdeps« zum Einsatz.

Control-Format

Das Control-Format definiert einen Standard, der in den »control«-Dateien von Binär- und den »dsc«-Dateien von Quelltext-Paketen sowie in den Files »Packages«, »Sources« und »Releases« der Paketdatenbank zum Einsatz kommt. Dabei handelt es sich um eine Variante des im RFC 822 für E-Mail-Header definierten Formats. Jede Zeile einer »control«-Datei enthält einen Feldnamen sowie den zugehörigen Wert:

Feldname: Wert

Beginnt eine Zeile mit einem Leerzeichen, interpretiert DPKG sie vollständig als Teil des zuletzt begonnenen Feldes. Leere Zeilen trennen Absätze voneinander und innerhalb eines Absatzes darf jeder Feldname nur einmal vorkommen. Mit »#« beginnende Zeilen ignoriert DPKG seit Debian-Version 3.1 (Sarge), allerdings interpretieren noch nicht alle Parser die Kommentare korrekt.

Der Befehl »dpkg-shlibdeps« wiederum setzt auf »ldd« und »objdump«, um die Bibliotheken zu bestimmen, von denen die ELF-Objekte des Pakets abhängen. Dann liest er mit »dpkg –search« die Namen der zugehörigen Pakete aus. Aus den »shlibs«-Dateien der ermittelten Pakete ergeben sich schließlich die Abhängigkeiten. »dpkg-shlibdeps« speichert sie in der Variablen »shlibs:Depends«.

Abbildung 2 illustriert die Aufgabenverteilung bei der Paketerstellung. Beispiele einfacher »debian/rules«- und »debian/control«-Dateien zeigen die Listings 1a und 1b. Die »rules«-Datei braucht man jedoch nicht vollständig manuell zu schreiben. Mehrere Werkzeuge automatisieren diesen Vorgang (Abbildung 3). Das wichtigste Tool dabei heißt »debhelper«, eine Sammlung von Skripten, die dem Paketbetreuer die meiste Arbeit abnehmen. Folgende Aufrufe erzeugen eine »rules«-Datei wie in Listing 1a:

dh_shlibdeps
dh_gencontrol
dh_builddeb

Dieses Vorgehen erspart nicht nur die Angabe der Kommandozeilenparameter, sondern führt auch zu einer flexibleren »rules«-Datei, denn die Debhelper-Skripte werten »debian/control« aus und behandeln alle darin erwähnten Pakete. Werden also in der Datei »debian/control« zusätzliche Pakete eingefügt, erstellt »dh_gencontrol« beim nächsten Aufruf automatisch auch für die zugehörigen Binärpakete die »control«-Dateien. Das Skript »dh_builddeb« ruft daraufhin auch »dpkg-deb« für alle aufgeführten Pakete auf.

Eine komplette Liste aller Helferskripte enthält die Debhelper-Manpage. Unter »/usr/share/doc/debhelper/examples« liefert das Paket außerdem noch einige »rules«-Beispieldateien mit. Der Debian New Maintainers\’ Guide [5] beschreibt den Vorgang zum Erstellen einer Deb-Datei unter Verwendung von Debhelper ausführlich.

Wig & Pen

Die derzeitige Form des Debian-Quellcode-Pakets unterliegt konzeptbedingt einigen Einschränkungen. So ist es damit recht aufwändig, binäre Daten wie Bilder über die Patch-Datei hinzuzufügen. Eine neue Version des Deb-Formats namens Wig & Pen [4] soll diesen Mangel beheben; derzeit spielt die als 2.0 bezifferte Version praktisch allerdings noch keine Rolle.

Zusätzlich zum Archiv ».orig.tar.gz« berücksichtigt das neue System weitere Tar-Archive, wenn sie dem Namensschema ».orig- Beschreibung.tar.gz« entsprechen. Deren Inhalte landen beim Auspacken in einem » Beschreibung« Verzeichnis unterhalb des Quellcode-Directory. So lassen sich beispielsweise auf verschiedene Tar-Archive verteilter Quellcode oder mehrere Programme in einem Paket zusammenfassen.

Patch-Archive

Alternativ zu einer einzelnen Patch-Datei für die Debian-spezifischen Änderungen liest Wig & Pen auch ein Tar-Archiv der Endung ».debian.tar.gz« aus, das mehrere Patches enthalten kann. Beim Entpacken landet sein Inhalt im Unterverzeichnis »debian/patches/« oder wird automatisch auf den Original-Quellcode angewandt.

Das neue Verfahren erleichtert den Umgang mit binären Dateien sowie mit komplexen Paketen, die im aktuellen System oft eine große und unübersichtliche ».diff.gz«-Datei enthalten. In der derzeit gängigen Praxis kommen mehrere einzelne Patch-Dateien nur mit Hilfe externer Tools wie »dpatch« oder »quilt« zum Einsatz. Darüber hinaus verwendet Wig & Pen optional auch das meist platzsparendere Kompressionsverfahren Bzip 2 statt des bisherigen Standards Gzip.

Zukunftsmusik

Bis sich die neue Version des Paketformats etabliert, wird aber noch einige Zeit vergehen. Die derzeit stabile Debian-Ausgabe Sarge unterstützt es noch gar nicht, die DPKG-Version des Nachfolgers Debian Etch kann Wig-&-Pen-Archive ausschließlich entpacken.

Es geht noch bequemer

Das Paket CDBS vereinfacht den Paketbau weiter. Es stellt spezialisierte Make-Dateien bereit, die sich über die »rules«-Datei einbinden lassen und die Operationen automatisch bestimmen. Für ein einfaches Paket mit einem Autotools-Build-System reduziert sich »rules« damit auf diese Zeilen:

#!/usr/bin/make -f
include /usr/share/cdbs/1/rules/debhelper.mk
include /usr/share/cdbs/1/class/autotools.mk

Um den Build-Prozesses später zu verändern, genügt es, einzelne Make-Variablen oder -Ziele anzupassen. Die Dokumentation dazu ist jedoch dürftig, so hilft oft nur das Studium der Makefiles des Upload-Pakets. Dennoch bevorzugen gerade Maintainer vieler sich gleichender Pakete CDBS, beispielsweise die Teams der großen Desktop-Umgebungen.

Die CDBS-Automatik kann jedoch durch irrige Annahmen zu schwer nachvollziehbaren Build-Fehlern führen. Der Komfort beim Paketbau setzt also genauere Tests der Ergebnisse voraus.

Ende ohne Schrecken

All diese Hürden auf dem Weg vom Originalprogramm über das Quellcode- zum fertigen Binärpaket bleiben einem Administrator beim Aufruf von »apt-get install Paketname« verborgen. Die lange Kette voneinander abhängiger Werkzeuge verliert glücklicherweise schon nach einigen wenigen Versuchen ihren Schrecken. Wer Pakete direkt so schnürt, dass sie auf jedem System funktionieren, weiß die damit verbundenen Vorteile bald zu schätzen. (csc)

Infos

[1] Debian-Policy: [http://www.debian.org/doc/debian-policy]

[2] Maintainer-Skripte: [http://women.alioth.debian.org/wiki/index.php/English/MaintainerScripts]

[3] Debian Library Packaging Guide: [http://www.netfort.gr.jp/~dancer/column/libpkg-guide]

[4] Wig & Pen: [http://www.dpkg.org/NewSourceFormat]

[5] Debian New Maintainers\’ Guide: [http://www.debian.org/doc/manuals/maint-guide]

Der Autor

Frank Lichtenheld ist seit 2002 im Debian-Projekt aktiv und arbeitet dort als Release-Assistant, Webmaster und Mitglied der QA-Gruppe.

LINUX-MAGAZIN KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Readly Logo
E-Mail Benachrichtigung
Benachrichtige mich zu:
0 Kommentare
Älteste
Neuste Beste Bewertung
Inline Feedbacks
Alle Kommentare anzeigen
Nach oben