Making midnight commander understand old and new RPM formats

Submitted by dag on Fri, 2010/07/30 - 16:32

If you are an avid fan of midnight commander (like me) and you happen to inspect RPM files from time to time (like me too), you may have been irritated by a change in the RPM format.

In the past the payload of the RPM package was a simple cpio file. You could use the rpm2cpio tool to extract the cpio payload from the RPM or simply open it using midnight commander.

Nowadays the payload is not a mere cpio archive, but an LZMA compressed cpio archive. And as a result you cannot open Fedora 13 or RHEL6 RPM packages on older RPM versions with the commands you are used to. Same problem with midnight commander (which bails out in an ugly way).

A few weeks ago I looked into the problem and fixed it on my RHEL5 system, the solution is quite simple, look at the RPMVERSION tag in the package, if it's newer than 4.7 process the rpm2cpio output with xz. What's more, I also implemented two types of payloads so it's visible from the directory listing whether it is a .cpio or a .cpio.xz. The patch looks like this:

And for some extra karma points I also added .xz and .lzma support in mc:

Now I have to look into who I have to send this to...

I doubt we will see this appear soon in RHEL5 :-/ But at least I can hapilly peek into RPM packages !

Update: I have added a new patch based on %{PAYLOADCOMPRESSOR} rather than %{RPMVERSION} ! Thanks to afb's comment.

%{RPMVERSION} ?

Wouldn't it be better to look at %{PAYLOADCOMPRESSOR} ?

Looking at PAYLOADCOMPRESSOR

Looking at PAYLOADCOMPRESSOR and RPMVERSION are mostly
unneeded. Add scripts/rpm2cpio on PATH for use by mc,
nothing else needs to change.

rpm2cpio.sh

I hope rpm2cpio.sh makes it through cut-and-paste. Otherwise
find same in any @rpm5.org release in scripts/rpm2cpio.

It simply isn't necessary to check RPMVERSION, just put the script
onto a MidnightCommander private path, add to PATH, nothing
else needs to change (but yes the scripte needs its pre-requisites.

=============================================

#!/bin/sh

pkg=$1
if [ "$pkg" = "" -o ! -e "$pkg" ]; then
echo "no package supplied" 1>&2
exit 1
fi

leadsize=96
o=`expr $leadsize + 8`
set `od -j $o -N 8 -t u1 $pkg`
il=`expr 256 \* \( 256 \* \( 256 \* $2 + $3 \) + $4 \) + $5`
dl=`expr 256 \* \( 256 \* \( 256 \* $6 + $7 \) + $8 \) + $9`
# echo "sig il: $il dl: $dl"

sigsize=`expr 8 + 16 \* $il + $dl`
o=`expr $o + $sigsize + \( 8 - \( $sigsize \% 8 \) \) \% 8 + 8`
set `od -j $o -N 8 -t u1 $pkg`
il=`expr 256 \* \( 256 \* \( 256 \* $2 + $3 \) + $4 \) + $5`
dl=`expr 256 \* \( 256 \* \( 256 \* $6 + $7 \) + $8 \) + $9`
# echo "hdr il: $il dl: $dl"

hdrsize=`expr 8 + 16 \* $il + $dl`
o=`expr $o + $hdrsize`
EXTRACTOR="dd if=$pkg ibs=$o skip=1"

COMPRESSION=`($EXTRACTOR |file -) 2>/dev/null`
if echo $COMPRESSION |grep -q gzip; then
DECOMPRESSOR=gunzip
elif echo $COMPRESSION |grep -q bzip2; then
DECOMPRESSOR=bunzip2
elif echo $COMPRESSION |grep -q xz; then
DECOMPRESSOR=unxz
elif echo $COMPRESSION |grep -q cpio; then
DECOMPRESSOR=cat
else
# Most versions of file don't support LZMA, therefore we assume
# anything not detected is LZMA
DECOMPRESSOR=`which unlzma 2>/dev/null`
case "$DECOMPRESSOR" in
/* ) ;;
* ) DECOMPRESSOR=`which lzmash 2>/dev/null`
case "$DECOMPRESSOR" in
/* ) DECOMPRESSOR="lzmash -d -c" ;;
* ) DECOMPRESSOR=cat ;;
esac
;;
esac
fi

$EXTRACTOR 2>/dev/null | $DECOMPRESSOR