OpenPKG Advent Calendar 2006

...every day a little pondering, backstage information, jokes, tips and tricks.
16
Saturday 2006-12-16: Tips & Tricks
Peeking into an OpenPKG RPM file

A good magician never reveals his secret;
the unbelievable trick becomes simple
and obvious once it is explained.

Dealing with OpenPKG is mainly about dealing with OpenPKG RPM package files. But what is actually in particular foo-*.src.rpm file?

RPM = Header + CPIO Payload

First, an OpenPKG RPM package file is nothing more than an OpenPKG RPM specific binary file header of just a few hundred bytes consisting of the essential header fields of the package specification — mainly just for quick querying them without having to unpack the package payload.

Second, there is this package payload: a bzip2(1) compressed cpio(1) archive of the package files. For a source package these are the package specification (foo.spec), vendor tarball(s) (foo-1.2.3.tar.gz), vendor patches (foo-1.2.3.patch), OpenPKG patch (foo.patch) and OpenPKG add-on files (rc.foo, fsl.foo, foo.conf, etc). For a binary package these are just the resulting installation files of the packaged vendor software.

rpm2cpio

You can check this out yourself by running the command openpkg rpm2cpio foo-*.src.rpm | cpio -itv to see the raw package payload. A similar output you can get with the command openpkg rpm -qlv foo-*.src.rpm. But while the first command on-the-fly provides a content listing based on the extracted cpio(1) archive, the second command just provides this information directly out of the RPM headers in front of the cpio(1) payload.

rpm2cpio emulation hack

That's all the magic behind an OpenPKG RPM package file. Remains just one nasty thing: openpkg rpm2cpio allows one to easily fiddle around with OpenPKG RPM package files without having to install them, but the command itself is part of an installed OpenPKG instance. But isn't there a way to unpack an OpenPKG RPM package file even without having anything of OpenPKG installed?

Well, the file format OpenPKG RPM uses is RPMv4 and if you really like puristic solutions you can use the following rpm2cpio emulating Perl script which is the smallest version known to us which is still able to correctly extract the cpio(1) payload of the RPMv4 format of an OpenPKG RPM package. Just store it as rpm2cpio and run it like perl rpm2cpio foo-*.src.rpm | cpio -itv. It requires just the basic Perl language features (and this way even runs under miniperl ;-) plus an externally available bzip2(1).

    open(RPM, "<$ARGV[0]") or die;
    open(CPIO, "|bzip2 -cd") or die;
    undef $/;
    read(RPM, $rpm, 96);
    ($magic, $major, $minor) = unpack("NCC", $rpm);
    read(RPM, $rpm, 16) or die;
    while (1) {
        ($magic, $crap, $sections, $bytes) = unpack("N4", $rpm);
        last if (substr($rpm, 0, 3) eq "BZh");
        seek(RPM, 16*$sections+$bytes, 1) or die;
        do {
            read(RPM, $rpm, 1) or die;
            $c = unpack("C", $rpm);
        } while ($c == 0x00);
        read(RPM, $rpm, 16-1, 1) or die;
    }
    while ($rpm ne '') {
        print(CPIO $rpm);
        read(RPM, $rpm, 16*1024);
    }
    close(CPIO);
    close(RPM);