Paketmanager opkg

Aus Vu+ WIKI
Wechseln zu: Navigation, Suche

opkg ist ein Paketmanager, zugeschnitten auf die Bedürfnisse von Embedded Systemen. Die Aufgabe eines Paketmanagers ist, die auf einem System (z.B. unseren VU+ Boxen) installierte Software zu verwalten. Die Software wird dazu in Pakete gebündelt. Mit dem Paketmanager können solche Pakete installiert, deinstalliert und gelöscht werden. Der Paketmanager ermöglicht es, Software-Pakete zentral zusammenzustellen und auch zentral zu verteilen. Dafür greift der Paketmanager auf den Feed zu - das ist das zentrale Repository, in dem alle Pakete zum Download für den Paketmanager bereitgestellt werden.

Benutzung

Für die komplette Liste der Befehle, die opkg kennt, gibt man einfach opkg in der Shell ein.

Die wichtigsten Befehle hier auf einen Blick:

opkg update Aktualisiert die Liste der am Feed verfügbaren Pakete
okpg list-upgradable Zeigt eine Liste aller Pakete an, für die es am Feed eine Aktualisierung gibt
opkg upgrade Aktualisiert alle Pakete, für die es eine neuere Version am Feed gibt
opkg list Zeigt eine Liste mit allen verfügbaren Paketen an
opkg list-installed Zeigt eine Liste mit allen installierten Paketen an
opkg install <paketliste> Installiert ein oder mehrere Pakete
opkg remove <paketliste> Deinstalliert ein oder mehrere Pakete

Weiterführende Informationen

Für die Benutzung des Paketmanagers sind die folgenden Informationen nicht wichtig. Das wird sich vermutlich ändern, wenn man selber Pakete bauen möchte.

opkg benutzt drei Verzeichnisse für den Betrieb:

/etc/opkg/ Konfiguration für opkg; hier wird die Liste aller Feeds abgelegt und die Liste der benutzten Architekturen definiert.
/var/lib/opkg/ Hier wird der Gesamt-Status der installierten Pakete gespeichert. Dies beinhaltet eine Liste aller Pakete, die am Feed verfügbar sind, als auch Listen mit allen Dateien, die von allen Paketen installiert wurden.
/usr/lib/opkg/ Im Verzeichnis /usr/lib/opkg/alternatives/ werden Informationen zu allen Programmen verwaltet, für die es mehrere Installations-Kandidaten gibt. Ein gutes Beispiel ist busybox, welches für eine Vielzahl von Standard-Unix-Programmen eine abgespeckte Variante zur Verfügung stellt. Wenn das Original-Programm ebenfalls installiert wird, soll natürlich nicht weiter die Busybox-Variante benutzt werden.

Paket-Informationen

Informationen zu allen installierten Paketen legt opkg im Verzeichnis /var/lib/opkg/info/ ab. In diesem Verzeichnis befinden sich zu jedem installierten Paket mehrere Dateien:

paketname.control Datei mit allen Meta-Informationen zum Paket paketname
paketname.list Liste aller vom Paket installierten Dateien
paketname.preinst (optional) Script, welches vor Installation von paketname ausgeführt wurde
paketname.postinst (optional) Script, welches nach Installation von paketname ausgeführt wurde
paketname.prerm (optional) Script, welches vor Deinstallation von paketname ausgeführt wird
paketname.postrm (optional) Script, welches nach Deinstallation von paketname ausgeführt wird
paketname.conffiles (optional) Liste aller vom Paket installierten Konfigurationsfiles, die beim Update nicht überschrieben werden sollen

Eine ipk-Datei ist vom Format eine ar-Datei, die immer 3 Dateien enthält:

control.tar.gz eine Tar-Datei mit den gerade beschriebenen Dateien aus /var/lib/opkg/info eines Paketes außer der .list-Datei
data.tar.gz eine Tar-Datei mit den zu installierenden Files; dies entspricht dem Inhalt der .list-Datei
debian-binary enthält immer 2.0 als String

Anmerkung: Neuere Versionen von opkg akzeptieren auch mit xz gepackte Tar-Dateien.

Mit diesen Informationen ist es einfach, zu einem installierten Paket wieder eine ipk-Datei mit einem installierbaren Paket zu bauen. Dafür kann folgendes Script benutzt werden:

   #!/bin/bash
   
   name=$1
   if [ ! -f "/var/lib/opkg/info/$name.control" ]; then
       echo "Paket " $name " ist nicht installiert"
   exit
   fi
   
   builddir=/media/hdd/build.$$
   mkdir $builddir || exit 1
   
   # control-, list- und p-Dateien ins Build-Dir kopieren
   pushd /var/lib/opkg/info > /dev/null
   for file in $name.*; do
       cp $file $builddir/${file#"$name."}
   done
   
   cd $builddir
   
   # tar-Datei mit allen gelisteten Dateien erstellen
   tar -czf data.tar.gz --no-recursion -T list 2>/dev/null
   
   # opkg benötigt für jedes Verzeichnis einen eigenen Eintrag,
   # deswegen das tar-File noch einmal aus- und wieder einpacken.
   mkdir clean
   cd clean
   tar -xf ../data.tar.gz
   tar -czf ../data.tar.gz .
   cd ..
   
   tar -czf control.tar.gz $(ls control conffiles pre* post* 2> /dev/null)
   echo "2.0" > debian-binary
   
   version=$(grep Version: control | sed -e 's/.*: *//')
   package=$(grep Package: control | sed -e 's/.*: *//')
   arch=$(grep Architecture: control | sed -e 's/.*: *//')
   
   ipk=${package}_${version}_${arch}.ipk
   
   ar r $ipk debian-binary control.tar.gz data.tar.gz 2> /dev/null
   popd > /dev/null
   
   mv -i $builddir/$ipk .
   rm -fr $builddir

Pakete selber bauen

Ein Paket ist eine Sammlung von zu installierenden Dateien, Metainformationen sowie vor und nach Installation auszuführenden Scripten. Als Paket-Container-Format wird dafür das unter Unix seit Ewigkeiten benutzte ar-Format verwendet, mit dem auch Bibliotheken für statische Libraries (.a-Files) erstellt werden.

In einer .ipk-Datei befinden sich immer drei Dateien: control.tar.gz, data.tar.gz, debian-binary. In der Datei control.tar.gz befinden sich alle Meta-Daten zum Programm:

  • control (diese Datei muss enthalten sein),
  • conffiles (optional Datei mit einer Liste von Konfigurationsfiles, die nicht überschrieben werden sollen; pro Zeile ein Filename - wird z.B. im Paket "base-files" benutzt, siehe /var/lib/opkg/info/base-files.* auf der Box)
  • preinst, prerm (optional, Shellscripten, die vor dem installieren bzw. löschen ausgeführt werden)
  • postinst, postrm (optional, Shellscripten, die nach dem installieren bzw. löschen ausgeführt werden)

Die Datei data.tar.gz beinhaltet die eigentlichen Paket-Daten, die installiert werden sollen. Die Datei data.tar.gz wird von opkg im Root-Verzeichnis ausgepackt. opkg benutzt dafür seinen eigenen Entpacker, der - im Gegensatz zu tar pingelig ist, was fehlende Verzeichnisse im Tar-File angeht.

Das control File

Bleibt noch das control-File zu erklären. Ein control-File besteht aus einer Reihe von Feld: Wert-Paaren, mit nachfolgend beschriebener Bedeutung. Dabei sind lediglich die Felder Package: und Architecture: Pflichtfelder, es ist aber sinnvoll, wenigstens noch Version: und Description: mit anzugeben.

  • Package: (Pflichtfeld) ist der Paket-Name ohne die Versions-Nummer
  • Architecture: (Pflichtfeld) bestimmt, unter welcher Architektur das Paket sinnvollerweise installiert werden kann. Hier nimmt man "all", wenn es unabhängig vom Prozessor ist, also z.B. ein Python-Script. Ansonsten z.B. armv7ahf-vfp-neon wenn es spezifisch für eine unserer 4k-Boxen ist, weil z.B. ein kompiliertes Binary enthalten ist. Gültige Werte für "Architecture" für deine Box stehen in der Datei /etc/opkg/arch.conf.
  • Version: (empfohlenes Feld) ist die Versionsnummer des Paketes. Hier fährt man sehr gut mit einer numerischen Versionsnummer (z.B. 1.2-r0), da opkg anhand der Versionsnummer alphanumerisch sortiert und entscheidet, ob ein Paket neuer als ein bereits installiertes ist. Versionsnummern a la "gitXXX" sind eher ungeeignet.
  • Description: (empfohlenes Feld) ausführliche Beschreibung des Pakets. Dieses Feld kann aus mehreren Zeilen bestehen, wobei nachfolgende Zeilen immer mit einem Leerzeichen beginnnen müssen, Absätze mit " .".
  • Depends: beschreibt die Abhängigkeiten zu anderen Paketen. Diese Zeile kann eine Liste von Paketen enthalten, die installiert sein müssen bzw. installiert werden sollen, wenn das Paket installiert wird. Für jedes Paket kann weiter noch angeben werden, welche Version benötigt wird. Das kann man durch (>> Version), (>= Version), (= Version), (<= Version), (<< Version) hinter dem Paketnamen angeben. >>: neuer als, >=: mindestens, =: genau gleich, <=: höchstens, <<: älter als.
  • Conflicts: wenn die Installation dieses Paketes sich mit einem anderen Paket beisst (z.B. wenn beide Pakete gleiche Files installieren), werden die Pakete durch Komma getrennt hier aufgeführt.
  • Installed-Size: hier kann der vom installierten Paket in Anspruch genommene Speicherplatz in KB angegeben werden
  • Maintainer: Wer betreut dieses Paket?
  • Priority: extra, optional, required, standard
  • Provides: Für kompliziertere Abhängigkeiten von Paketen mit virtuellen Paketen definiert "Provides:", für welches virtuelle Paket das Paket eine Installation erfüllt. Dafür kann ein Paket z.B. "Depends: vpaket" voraussetzen, und unser Paket "Package: paket" sowie "Provides: vpaket" definieren. Das macht man gerne, wenn man Pakete für spezifische Hardware schnürt, z.B. eine bestimmte Box.
  • Section: Welcher Sektion das Paket zugeordnet werden soll.
  • Replaces: Manchmal gibt es für ein altes Paket ein neues, welches das alte ersetzt. Um Konflikte mit gleichen Files zu verhindern, kann man hier angeben, welches alte Paket unser Paket ersetzt.
  • Source: Quelle des Pakets.
  • Recommends: Liste von Paketen, für die es Sinn macht, zusätzlich zu diesem Paket installiert zu werden. Quasi eine sehr weiche Depends: Klausel.
  • Suggests: Liste von Paketen, für die es vielleicht Sinn macht, zusätzlich zu diesem Paket installiert zu werden - eine noch weichere Depends: Klausel.

Als Beispiele kann man sich die tausenden von *.control im Verzeichnis /var/lib/opkg/info/ anschauen. Pro installiertes Paket steht dort die control-Datei, die mit dem Paket ausgeliefert wurde.

Ein Script um Pakete zu erstellen

Mit folgendem Script kann aus einem Installations-Verzeichnis heraus ein fertiges Paket gebaut werden. Dafür ist es nur nötig, eine fertige control-Datei und das fertige data.tar.gz im Verzeichnis abzulegen. Wenn man ein Programm fertig kompiliert hat, lässt es sich üblicherweise mit dem Kommando make install installieren. Man kann aber bei den meisten Programmen heute make install DESTDIR=/media/hdd/install angeben, um das Programm unter einem anderen Root-Verzeichnis, z.B. /media/hdd/install/, zu installieren. Von hier kann man noch einmal schauen, was alles installiert würde, und von hier das data.tar.gz-File erstellen.

Das folgende Script wird im Installations-Root (z.B. /media/hdd/install/) ausgeführt:

   #!/bin/bash
   
   if [ ! -f "control" -o ! -f "data.tar.gz" ]; then
       echo "Verzeichnis enthält keine Paketdaten"
       exit
   fi
   
   tar -czf control.tar.gz $(ls control conffiles pre* post* 2> /dev/null)
   echo "2.0" > debian-binary
   
   version=$(grep Version: control | sed -e 's/.*: *//')
   package=$(grep Package: control | sed -e 's/.*: *//')
   arch=$(grep Architecture: control | sed -e 's/.*: *//')
   
   ipk=${package}_${version}_${arch}.ipk
   
   ar r $ipk debian-binary control.tar.gz data.tar.gz

Wichtig: für dieses Script wird das ar aus den Binutils benötigt, hier funktioniert das ar aus Busybox nicht. Ein Binutils-Paket für die ARM-Architektur findet sich bei uns im Downloads-Bereich, für MIPSEL wird man fündig, wenn man im Netz nach Debian-Paketen sucht.