Tuesday, March 25, 2008

Creating Linux RPM's From Already Installed Packages

rpm_remk creating a new Mutt RPM


Click on the image for a higher resolution version of the output shown above!

Hey there,

Today's post is a follow up to, or the complement of, a post we did a little while ago on creating Solaris pkg files from already installed packages. Yes, there was a reason today's title sounded familiar ;)

Actually, I've been meaning to follow up on the Linux counterpart of this issue for a week or so now, but got caught up trying out various things. For instance, one of the more unusual (and interesting things) I ran across was a Perl project called alien that endeavours to pretty much translate between almost all package formats (dpkg, rpm, pkg, etc), but it didn't really address this specific issue. Still, pretty neat and in the experimental stage.

I also followed a lot of trial and error using rpmrebuild and standard rpm with the --repackage option, but found that both of these methods required the additional execution of at least one thing I didn't need to do to achieve my goal. For instance, using rpm with the --repackage option requires that you be upgrading, re-installing, deleting, etc, the RPM in question. All I want to do is create a package from existing source, and I'd rather not have to upgrade, re-install or delete the software on a live system to do it :)

Luckily, in the end, it boiled down to a fairly simple process. A lot of confusion came from various interpretations of the rpmbuild "spec file" and how, and why, it should be used. Many of the ideas I got that led me to an eventual solution came off of message boards rather than official sources. To put it somewhat humorously, a lot of those guys may not know what they're talking about, but they sure do know what they're doing ;) Seriously, if it weren't for the folks who strayed from the info-docs, this solution might have taken even longer to come around to.

You can call today's command (which I've name "rpm_remk" to remind me of my similar Solaris pkg project), very simply from the command line, like so:

host # ./rpm_remk mutt <--- If, for example, you wanted to create an RPM of the installed version of "mutt" on your system.

You can be as specific or general as RPM will let you when you use this command. For instance, on my box, I only have one instance of mutt:

host # rpm -qa|grep mutt
mutt-1.5.6i-64.9


So that simple command line suffices. For another program like, say, xaw3d, I would have to be more specific, because the underlying RPM system wouldn't know which package I was referring to. For example:

host # rpm -qa|grep xaw3d
xaw3d-1.5E-216.3
xaw3d-32bit-9-200407011229


Shows two different selections. RPM generally only picks the first one, like this:

host # rpm -q xaw3d
xaw3d-1.5E-216.3


So, if we ran the command with only "xaw3d" as the argument, we'd create that 1.5E RPM, which would be great unless we wanted the 32bit version ;) Specifying "xaw3d-32bit-9-200407011229" as the argument would guarantee that the intended RPM got built!

Here's hoping this script helps you out and makes it a little easier for you to retrieve some of those old installed software packages for which the original RPM's have long since disappeared :)


Creative Commons License


This work is licensed under a
Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License

#!/bin/bash

# rpm_remk - Create new RPM's from installed RPM's
#
# 2008 - Mike Golvach - eggi@comcast.net
#
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#

trap 'rm -rf $temp_var;exit 1' 1 2 3 9 15
if [ $# -ne 1 ]
then
echo "Usage: $0 PackageName"
exit 1
fi

existing_rpm=$1
starting_point=`pwd`
temp_var=$$

mkdir ${starting_point}/RPMS
mkdir ${starting_point}/RPMS/noarch
mkdir ${starting_point}/RPMS/`uname -i`
mkdir $temp_var
cd $temp_var

if [ `expr match \`rpm -q --queryformat "%{INSTALLPREFIX}\n" $existing_rpm\` '(none)'` -ne 0 ]
then
Prefix="/"
else
Prefix=`rpm -q --queryformat "Prefix: %{INSTALLPREFIX}\n" $existing_rpm`
fi

echo "%define _topdir $starting_point" >>$existing_rpm.spec
rpm -q --queryformat "Summary: %{SUMMARY}\n" $existing_rpm >>$existing_rpm.spec
rpm -q --queryformat "Name: %{NAME}\n" $existing_rpm >>$existing_rpm.spec
rpm -q --queryformat "Version: %{VERSION}\n" $existing_rpm >>$existing_rpm.spec
rpm -q --queryformat "Release: %{RELEASE}\n" $existing_rpm >>$existing_rpm.spec
rpm -q --queryformat "Copyright: %{COPYRIGHT}\n" $existing_rpm >>$existing_rpm.spec
rpm -q --queryformat "Group: %{GROUP}\n" $existing_rpm >>$existing_rpm.spec
echo "Prefix: $Prefix" >>$existing_rpm.spec
description=`rpm -q --queryformat "%{DESCRIPTION}\n" $existing_rpm`
echo "%description" >>$existing_rpm.spec
echo "$description" >>$existing_rpm.spec
echo "%files" >>$existing_rpm.spec
rpm -ql $existing_rpm|while read x
do
echo "%{prefix}$x" >>$existing_rpm.spec
done

rpmbuild -bb $existing_rpm.spec 2>&1|grep -v twice
cd $starting_point
mv -f ${starting_point}/RPMS/*/* .
rm -rf $temp_var ${starting_point}/RPMS


, Mike