208

I have an rpm and I want to treat it like a tarball. I want to extract the contents into a directory so I can inspect the contents. I am familiar with the querying commands of an uninstalled package. I do not simply want a list of the contents of the rpm. i.e.

$ rpm -qpl foo.rpm

I want to inspect the contents of several files contained in the rpm. I do not want to install the rpm. I am also aware of the rpms ability to do additional modifictions in the %post sections, and how to check for those. i.e.

$ rpm -qp --scripts foo.rpm

However in this case that is of no concern to me.

19 Answers 19

252

Did you try the rpm2cpio commmand? See the example below:

$ rpm2cpio php-5.1.4-1.esp1.x86_64.rpm | cpio -idmv

/etc/httpd/conf.d/php.conf  
./etc/php.d  
./etc/php.ini  
./usr/bin/php  
./usr/bin/php-cgi  
etc 
11
  • 44
    I'm amazed that Linux distributions do not provide a wrapper executable to make this easier (eg rpmextract bla.rpm), as this is a very common operation. User should not need to care about the intermediary cpio format. Commented Sep 24, 2014 at 22:32
  • 4
    Don't be amazed, @AlanEvangelista, this is par for the course.
    – ngreen
    Commented Oct 30, 2014 at 19:59
  • 17
    @AlanEvangelista I'm amazed that rpm is such bad format. Comparing to other like deb which are just simple archives adhering to UNIX philosophy. Commented Mar 3, 2015 at 11:07
  • 8
    In my case I was getting cpio: Malformed number errors with this command. What worked for me is running rpm2archive xorg-x11-server-1.20.11-1.fc33.src.rpm, and then tar -xzvf xorg-x11-server-1.20.11-1.fc33.src.rpm.tgz to extract into the current dir.
    – Hi-Angel
    Commented Jul 11, 2021 at 14:00
  • 7
    @Hi-Angel It's because RHEL 9 uses a payload compression (zstd), I added an answer, this is another method to extract it: rpm2cpio foo.rpm | zstd -d | cpio -idmv
    – G. C.
    Commented Oct 31, 2022 at 10:32
100
$ mkdir packagecontents; cd packagecontents
$ rpm2cpio ../foo.rpm | cpio -idmv
$ find . 

For Reference: the cpio arguments are

-i = extract
-d = make directories
-m = preserve modification time
-v = verbose

I found the answer over here: lontar's answer

1
  • 2
    "rpm2cpio foo.rpm | cpio -idmv" works for me. It is sufficient to extract the contents of the rpm at current path.
    – parasrish
    Commented Apr 21, 2016 at 7:24
41

For those who do not have rpm2cpio, here is the ancient rpm2cpio.sh script that extracts the payload from a *.rpm package.

Reposted for posterity … and the next generation.

Invoke like this: ./rpm2cpio.sh .rpm | cpio -dimv

#!/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 -iq xz; then # xz and XZ safe
        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
1
  • I get this error "unlzma: bad lzma header" using Alpine Linux. Tried multiple rpms.
    – jekennedy
    Commented Aug 29, 2018 at 15:12
34

Sometimes you can encounter an issue with intermediate RPM archive:

cpio: Malformed number
cpio: Malformed number
cpio: Malformed number
. . .
cpio: premature end of archive

That means it could be packed, these days it is LZMA2 compression as usual, by xz:

rpm2cpio <file>.rpm | xz -d | cpio -idmv

otherwise you could try:

rpm2cpio <file>.rpm | lzma -d | cpio -idmv
4
  • 1
    lifesaver. @LasseHalbergHaarbye i added it to the accepted answer. Commented Dec 30, 2016 at 22:45
  • I was getting the "Malformed number" and "premature end of archive" errors but neither of the posted solutions worked for me. I had to do rpm2cpio <file>.rpm | bsdtar -xf - (no cpio) for it to work.
    – jackkamm
    Commented Aug 30, 2017 at 6:52
  • 1
    The intermediate archive ended up being gzip-formatted for me, so I used gunzip instead of xz or lzma which worked fine.
    – jayhendren
    Commented Oct 30, 2019 at 19:27
  • 2
    For newer packages (RHEL 9) use zstd -d, like this: rpm2cpio <file>.rpm | zstd -d | cpio -idmv Commented Oct 27, 2022 at 11:22
13

Most distributions have installed the GUI app file-roller which unpacks tar, zip, rpm and many more.

file-roller --extract-here package.rpm

This will extract the contents in the current directory.

1
  • Great answer! file-roller can handle *.rpm as input, and rpm2cpio does not... Commented Dec 15, 2023 at 12:53
7

You can simply do tar -xvf <rpm file> as well!

5
  • 1
    Unable to reproduce that with an .rpm package. You might want to correct your answer.
    – gvlasov
    Commented Feb 10, 2015 at 20:49
  • 12
    This works on OS X - or any other system that uses a variant of tar which uses libarchive under the hood.
    – Glenjamin
    Commented Dec 1, 2015 at 9:01
  • 4
    I got the error: This does not look like a tar archive. Commented Apr 13, 2018 at 5:27
  • This worked for me on MacOS 10.14.1 with bsdtar 2.8.3 - libarchive 2.8.3. It might depend on which type of compression was used. The rpm2cpio.sh script seems to check for several types of compression before passing it to the right tool for extraction.
    – 2xj
    Commented Dec 5, 2018 at 20:20
  • 1
    Since SO's edit functionality won't let me add 3 characters to fix the answer, it should be added that this requires libarchive's bsdtar. Homebrew on Mac links tar to it by default but on other OSs tar means GNU tar.
    – Atemu
    Commented Sep 18, 2019 at 20:54
7

7-zip understands most kinds of archives, including rpm and the included cpio.

1
  • I have tried with 7 zip and it has perfectly worked. Commented Jan 30, 2020 at 16:26
6

As reported here: https://bugzilla.redhat.com/show_bug.cgi?id=2058426

RHEL 9 uses a payload compression (zstd)

rpm2cpio foo.rpm | zstd -d | cpio -idmv
5

The powerful text-based file manager mc (Midnight Commander, vaguely reminding the Norton Commander of old DOS times) has the built-in capability of inspecting and unpacking .rpm and .rpms files, just "open" the .rpm(s) file within mc and select CONTENTS.cpio: for an rpm you get access to the install tree, for an rpms you get access to the .spec file and all the source packages.

4

To debug / inspect your rpm I suggest to use redline which is a java program

Usage :

java -cp redline-1.2.1-jar-with-dependencies.jar org.redline_rpm.Scanner foo.rpm

Download : https://github.com/craigwblake/redline/releases

3

In NixOS, there is rpmextract. It is a wrapper around rpm2cpio, exactly as @Alan Evangelista wanted. https://github.com/NixOS/nixpkgs/tree/master/pkgs/tools/archivers/rpmextract

2

In OpenSuse at least, the unrpm command comes with the build package.

In a suitable directory (because this is an archive bomb):

unrpm file.rpm
2

On Manjaro using KDE, Ark can handle it.

2

If your system has rpm2archive installed, you can run:

rpm2archive package.rpm

This converts rpm package into a compressed tar archive package.rpm.tgz. Now you can extract it using:

tar -xvf package.rpm.tgz

This was earlier noted by Hi-Angel in his comment.

Sources:

  1. rpm2archive man page
  2. It was released with rpm 4.12.0-alpha (it's fairly new)
  3. On Debian and its derivatives, it is included with rpm2cpio package.
2

If you have rpmdevtools installed, you can also extract the RPM package file with just one command:

rpmdev-extract foo.rpm
1

Copy the .rpm file in a separate folder then run the following command $ yourfile.rpm | cpio -idmv

1
  • 2
    this should be comment
    – ketan
    Commented Apr 21, 2016 at 4:39
1

The "DECOMPRESSION" test fails on CygWin, one of the most potentiaally useful platforms for it, due to the "grep" check for "xz" being case sensitive. The result of the "COMPRESSION:" check is:

COMPRESSION='/dev/stdin: XZ compressed data'

Simply replacing 'grep -q' with 'grep -q -i' everywhere seems to resolve the issue well.

I've done a few updates, particularly adding some comments and using "case" instead of stacked "if" statements, and included that fix below

#!/bin/sh
#
# rpm2cpio.sh - extract 'cpio' contents of RPM
#
# Typical usage: rpm2cpio.sh rpmname | cpio -idmv
#

if [ "$# -ne 1" ]; then
    echo "Usage: $0 file.rpm" 1>&2
    exit 1
fi

rpm="$1"
if [ -e "$rpm" ]; then
    echo "Error: missing $rpm"
fi


leadsize=96
o=`expr $leadsize + 8`
set `od -j $o -N 8 -t u1 $rpm`
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 $rpm`
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=$rpm ibs=$o skip=1"

COMPRESSION=`($EXTRACTOR |file -) 2>/dev/null`
DECOMPRESSOR="cat"

case $COMPRESSION in
    *gzip*|*GZIP*)
        DECOMPRESSOR=gunzip
        ;;
    *bzip2*|*BZIP2*)
        DECOMPRESSOR=bunzip2
        ;;
    *xz*|*XZ*)
        DECOMPRESSOR=unxz
        ;;
    *cpio*|*cpio*)
        ;;
    *)
        # 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="$DECOMPRESSOR"
                ;;
            *)
                DECOMPRESSOR=`which lzmash 2>/dev/null`
                case "$DECOMPRESSOR" in
                    /* )
                        DECOMPRESSOR="lzmash -d -c"
                        ;;
                    *  )
                        echo "Warning: DECOMPRESSOR not found, assuming 'cat'" 1>&2
                        ;;
                esac
                ;;
        esac
esac

$EXTRACTOR 2>/dev/null | $DECOMPRESSOR
1

If you have tried the rpm2cpio.sh script above and it didn't work, you can save the follwing script and invoke like this: rpm2cpio.sh rpmname | cpio -idmv, it workes on my CentOS 7.

#!/bin/sh -efu

fatal() {
    echo "$*" >&2
    exit 1
}

pkg="$1"
[ -n "$pkg" ] && [ -e "$pkg" ] ||
    fatal "No package supplied"

_dd() {
    local o="$1"; shift
    dd if="$pkg" skip="$o" iflag=skip_bytes status=none $*
}

calcsize() {

    case "$(_dd $1 bs=4 count=1 | tr -d '\0')" in
        "$(printf '\216\255\350')"*) ;; # '\x8e\xad\xe8'
        *) fatal "File doesn't look like rpm: $pkg" ;;
    esac

    offset=$(($1 + 8))

    local i b b0 b1 b2 b3 b4 b5 b6 b7

    i=0
    while [ $i -lt 8 ]; do
        # add . to not loose \n
        # strip \0 as it gets dropped with warning otherwise
        b="$(_dd $(($offset + $i)) bs=1 count=1 | tr -d '\0' ; echo .)"
        b=${b%.}    # strip . again

        [ -z "$b" ] &&
            b="0" ||
            b="$(exec printf '%u\n' "'$b")"
        eval "b$i=\$b"
        i=$(($i + 1))
    done

    rsize=$((8 + ((($b0 << 24) + ($b1 << 16) + ($b2 << 8) + $b3) << 4) + ($b4 << 24) + ($b5 << 16) + ($b6 << 8) + $b7))
    offset=$(($offset + $rsize))
}

case "$(_dd 0 bs=4 count=1 | tr -d '\0')" in
    "$(printf '\355\253\356\333')"*) ;; # '\xed\xab\xee\xdb'
    *) fatal "File doesn't look like rpm: $pkg" ;;
esac

calcsize 96
sigsize=$rsize

calcsize $(($offset + (8 - ($sigsize % 8)) % 8))
hdrsize=$rsize

case "$(_dd $offset bs=2 count=1 | tr -d '\0')" in
    "$(printf '\102\132')") _dd $offset | bunzip2 ;; # '\x42\x5a'
    "$(printf '\037\213')") _dd $offset | gunzip  ;; # '\x1f\x8b'
    "$(printf '\375\067')") _dd $offset | xzcat   ;; # '\xfd\x37'
    "$(printf '\135')") _dd $offset | unlzma      ;; # '\x5d\x00'
    "$(printf '\050\265')") _dd $offset | unzstd  ;; # '\x28\xb5'
    *) fatal "Unrecognized payload compression format in rpm file: $pkg" ;;
esac
-1

simply run this:

$rpm -ivh package_name.rpm

if you don't have super user permissions, use sudo -i command then execute this.
if you don't have rpm package, install rpm package.

2
  • Seems not working for me. I got the following error: warning: rstudio-server-rhel-2021.09.2-382-x86_64.rpm: Header V4 RSA/SHA256 Signature, key ID e331692f: NOKEY error: can't create transaction lock on /var/lib/rpm/.rpm.lock (Permission denied)
    – Haizi
    Commented Jan 17, 2022 at 16:30
  • 1
    Caution! This does not only extract the RPM, but also installs it on the system. Commented Jan 13, 2023 at 17:50

Not the answer you're looking for? Browse other questions tagged or ask your own question.