Quellcode-Patches in RPM-Dateien integrieren

Neulich habe ich die Software scponly mittels rpmbuild für Enterprise Linux paketiert und bin dabei auf eine Fehlermeldung gestoßen:

 1$ cd ~/rpmbuild/SPECS
 2$ rpmbuild -ba scponly.spec
 3checking for libgiertz...
 4...
 5/usr/bin/install -c -o 0 -g 0 scponly /home/cstan/rpmbuild/BUILDROOT/scponly-4.8-1.el7.centos.x86_64/usr/bin/scponly
 6/usr/bin/install: cannot change ownership of '/home/cstan/rpmbuild/BUILDROOT/scponly-4.8-1.el7.centos.x86_64/usr/bin/scponly': Operation not permitted
 7make: *** [install] Error 1
 8error: Bad exit status from /var/tmp/rpm-tmp.Zx3wsc (%install)
 9
10RPM build errors:
11    Bad exit status from /var/tmp/rpm-tmp.Zx3wsc (%install)

Beim "Installieren" der übersetzten Dateien innerhalb des RPM-Pakets schlägt also das Ändern des Dateibesitzers fehl - aber warum? Das Makefile sollte hier Aufschluss geben. Unterhalb des BUILD-Ordners befinden sich Laufzeitdaten von vorherigen Übersetzungsprozessen:

 1$ cd ../BUILD/scponly-3xxx
 2$ less Makefile.in
 3...
 4        ${INSTALL} -o 0 -g 0 scponly ${DESTDIR}${bindir}/scponly
 5        ${INSTALL} -o 0 -g 0 -m 0644 scponly.8 ${DESTDIR}${mandir}/man8/scponly.8
 6        ${INSTALL} -o 0 -g 0 -m 0644 debuglevel ${DESTDIR}${DEBUGFILE}
 7        if test "x${CHROOTED_NAME}" != "x"; then                        
 8                ${INSTALL} -d ${DESTDIR}${sbindir};                             
 9                rm -f ${DESTDIR}${sbindir}/${CHROOTED_NAME};                    
10                cp scponly ${CHROOTED_NAME};                            
11                ${INSTALL} -o 0 -g 0 -m 4755 ${CHROOTED_NAME} ${DESTDIR}${sbindir}/${CHROOTED_NAME};

Beim Konsultieren des Makefiles fielen mir die install-Parameter -o und -g auf. Mithilfe dieser Parameter kann ein spezieller Benutzer bzw. eine spezielle Gruppe angegeben werden - 0 steht hier für den root-Benutzer bzw. die root-Gruppe. Beim Erstellen von RPM-Paketen ist das spezielle Definieren von root an dieser Stelle überflüssig, da - sofern nicht anders angegeben - jede Datei erstmal root gehört.

Bei einem manuellen Übersetzen der Software hat sich gezeigt, dass der Prozess ohne die oben erwähnten Parameter fehlerfrei durchläuft. Nun muss nur der Quellcode gepatcht werden, damit das RPM-Paket fehlerfrei erstellt werden kann.

Hierfür muss zuerst eine Kopie des entsprechenden Ordners erstellt werden - wir befinden uns wieder im BUILD-Ordner:

1$ cd ..
2$ mkdir scponly-3xxx-revised
3$ cp -R scponly-3xxx scponly-3xxx-revised

Nun wird die entsprechende Datei - hier das Makefile - angepasst:

 1$ vi scponly-3xxx-revised/Makefile.in
 2...
 3        ${INSTALL} scponly ${DESTDIR}${bindir}/scponly
 4        ${INSTALL} -m 0644 scponly.8 ${DESTDIR}${mandir}/man8/scponly.8
 5        ${INSTALL} -m 0644 debuglevel ${DESTDIR}${DEBUGFILE}
 6        if test "x${CHROOTED_NAME}" != "x"; then
 7                ${INSTALL} -d ${DESTDIR}${sbindir};
 8                rm -f ${DESTDIR}${sbindir}/${CHROOTED_NAME};
 9                cp scponly ${CHROOTED_NAME};
10                ${INSTALL} -m 4755 ${CHROOTED_NAME} ${DESTDIR}${sbindir}/${CHROOTED_NAME};
11ESC ZZ

Anschließend wird mittels diff ein Vergleich der beiden Verzeichnisse durchgeführt - die Änderungen werden in einer Patch-Datei dokumentiert. Idealerweise legt man diese direkt im SOURCES-Ordner ab, wo sich auch bereits der Programmquellcode befindet. Das ist wichtig, damit im RPM Specfile darauf verwiesen werden kann!

1$ diff -urN scponly-3xxx scponly-3xxx-revised > ../SOURCES/scponly-3xxx-makefile.patch

Im RPM Specfile wird nun nach der Source-Zeile eine Patch-Zeile eingefügt, die den Dateinamen des Patches enthält . In der %prep-Sektion der Datei wird nach der %setup-Zeile eine neue Zeile zum Patchen des Quellcodes eingefügt: %patch0 -p1.

Natürlich ist es auch möglich, mehrere Patches zu referenzieren - die Zeilen enthalten eine fortlaufende Nummer. In diesem Fall wurde der erste Patch referenziert - daher heißen die Schlagwörter Patch0 bzw. %patch0:

 1$ cd ../SPECS
 2$ vi scponly.spec
 3...
 4Source0:        https://github.com/scponly/scponly/archive/3xxx.zip
 5Patch0:         scponly-3xxx-makefile.patch
 6...
 7%prep
 8%setup -q -n scponly-3xxx
 9%patch0 -p1
10...
11
12ESC ZZ

Anschließend ließ sich das RPM-Paket wie gewohnt erstellen:

1$ rpmbuild -ba scponly.spec
2...
3Executing(%clean): /bin/sh -e /var/tmp/rpm-tmp.jchHSk
4+ umask 022
5+ cd /home/cstan/rpmbuild/BUILD
6+ cd scponly-3xxx
7+ /usr/bin/rm -rf /home/cstan/rpmbuild/BUILDROOT/scponly-4.8-1.el7.centos.x86_64
8+ exit 0

Wenn man einen Blick in das RPM-Paket wirft (beispielsweise mit cpio oder Midnight Commander), sieht man, dass die Dateien root gehören - es gibt also keine Beeinträchtigung der Software nach Übernahme des Patches:

1-rw-r--r--    1 root    root                        2 Jun 30 18:22 /etc/scponly/debuglevel
2-rwxr-xr-x    1 root    root                    24720 Jun 30 18:22 /usr/bin/scponly
3-rwxr-xr-x    1 root    root                    24720 Jun 30 18:22 /usr/sbin/scponlyc
4-rw-r--r--    1 root    root                     2534 Jun 30 18:22 /usr/share/man/man8/scponly.8.gz

Wer das Beispiel gerne nachstellen möchte, kann gerne mein RPM Spec und den Patch verwenden.

Übersetzungen: