
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 :)
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
linux unix internet technology
Tuesday, March 25, 2008
Creating Linux RPM's From Already Installed Packages
Friday, March 14, 2008
Using Pkgbuild To Build Solaris Pkg Files Just Like Linux RPM's
Hello again,
If you're a regular reader, you've probably noticed that I've been spending a whole lot of time looking at ways to build packages, automate installations, etc, on both Linux and Unix ;) One interesting thing I found in my downloading, testing and trial is an ambitious project called pkgbuild, which is a good attempt (ongoing, and getting better) at addressing Solaris' pkg creation system and making it as versatile and security-conscious as RedHat's "rpmbuild" (That we took a look at a lot more than a few times in our series on creating your own RPM's.
The software's two main attractions are that it:
1. Addresses the "spec file" format for configuring software builds, just like rpmbuild
and
2. It works just about the same way. For instance, if you had your "spec file" written up and were ready to compile the source and binary pkg's for your build, you could do it almost exactly the same way we built our RPMS. The only difference on the command line, in fact, is the name of the command:
host # pkgbuild -ba PROGRAM.spec <--- eerily familiar ;)
The "spec file" format is almost identical to rpmbuild, except that there are some specific Solaris pkg tags that need to be used within the "header section" (Since, technically, you're still building a package and we know what Sun expects from Solaris pkg's "pkginfo" file. The following extra defines are specific to the pkgbuild software's "spec file":
SUNW_BaseDir "DIR" <--- Same as BASEDIR in the pkginfo file. Defaults to /, just like on Solaris.
SUNW_Pkg "PKG_NAME" <--- Same as NAME. Like SUNWblah
SUNW_ProdName "PRODNAME" <--- Same as SUNW_PRODNAME. Usually "SunOS"
SUNW_ProdVers "VERSION" <--- Same as SUNW_PRODVERS. For instance "5.9" for Solaris 9.
SUNW_Category "CATEGORY" <--- Same as CATEGORY. Generally "application"
SUNW_HotLine "WHO TO CALL" <--- Same as HOTLINE. Can include an email or who to contact about the pkg. Not necessary, but available :)
The list is actually fairly extensive and still growing. You can check it out here in the pkgbuild online manual
They also include support for %include directives, as well as all the stuff you'd expect, like inline macros for doing the "configure," "build," and "install" portions of your pkg creation.
The only downside (and it's pretty big) that I see so far is that the pkgbuild format and build process doesn't meld seamlessly enough to make it what I think it's trying to be (a way to provide admins with one simple way to create both Linux RPM's and Solaris pkg's). At this point, in the end, it's basically making you jump through a lot of hoops to get it to do what you would normally do if you were making the pkg file yourself. Still, it's early and I haven't counted it out yet.
I'll be writing more about this as I get into it and work it into our business practices. Until then, it might be worth checking out. If your business involves creating and/or packaging software installations for Solaris, this will, at the very least, be highly interesting :)
Best wishes,
, Mike
linux unix internet technology
Thursday, March 6, 2008
Finalizing The Spec File And Building Your Own Linux RPM
Hey There,
We're finally ready to create our very own Linux RPM package! Following up on yesterday's post regarding beginning to write your spec file and the preceding initial software build, we're now going to look at the "build" section of the RPM spec file and compile our new RPM.
The "build" section of the spec file follows the "header section" we went over previously, and contains all that the "rpmbuild" command needs to know in order to create your RPM for you. I should note here that, on some systems, this command may be called "rpm-build" and, on yet others, the rpmbuild flags may simply be options to the rpm command itself (as with SUSE 8.x)
The declarations required in this section are:
%clean <--- Well, not really required, but keeps things nice and tidy ;)
%prep
%setup
%files
%build
%install
These sections are defined as follows (Note that for these declarations, the values are listed beginning on the line below, rather than on the same line, as we did in the "header section":
%clean - this deletes everything in the RPM_BUILD_ROOT, as defined by either the BuildRoot declaration in the "header section" (Which we didn't use for this build) or by the system default. In our case, this should be /usr/src/packages/BUILD. Cautious users may want to add a line of code in front of this, assuring that the RPM_BUILD_ROOT variable isn't set to /. This method is not absolutely necessary, either, so the incredibly cautious can just not call it and remove old garbage files, whenever they want to, manually. It can also cause issues when running concurrent builds if using the same RPM_BUILD_ROOT! Some folks prefer to run this method at the end of the spec file, or script out what it does automatically. It's a matter of preference :)
%prep - This simply indicates that we're moving on to the next section of our spec file. It is necessary, as everything beyond it will be considered part of the build process, rather than part of the RPM definition process, listed above it.
%setup - This part of the spec file indicates that "rpmbuild" should do whatever is necessary to prepare the source for building/compilation. Of course, we've done this already (to make sure we could build from source properly), but this declaration is necessary so that rpmbuild sets everything up for the following sections. Note that without any arguments, in our setup, it's just going to unzip and untar our source package in /usr/src/packages/SOURCES to the /usr/src/packages/BUILD directory.
%files - This is where we have to list all of the files that are going to be in our RPM, for reference when its installed and/or removed using the "rpm" command. In our previous post on building the software from source, we created a file called FILELIST (from the output of the find command). On the line following the %files declaritive, you can just read that file list into your spec file. If you elect to type each file name in, that's your decision, but you should include only one file per line (which can make your spec file pretty long depending on what you're installing. Given how many files most software packages contain, you'll grow sick and tired of this method soon enough ;)
%build - Here you'll provide all the information required to build the software. This can be culled from the notes you took while compiling the program initially.
%install - And finally, here you'll provide all the information required to install the program (Basically, the "make install" command and all arguments from the original compile of the software that you did earlier.
Our spec file will look something like this:
%clean
%prep
%setup
%files
/usr/local/PACKAGE-3.2-1/bin/list
/usr/local/PACKAGE-3.2.1/lib/liblist.so
...
%build
./configure --prefix=%{prefix}
make
make check
%install
make install
/bin/chown -Rv root:root %{prefix}
Before we actually build our RPM, we'll want to change the names of all the files listed in the %files section, that we got from our initial build. Assuming you wanted the RPM to install in /usr/local, you would want to use your favorite editor to replace all instances of "/usr/local/PACKAGE-3.2-1" in this section with "/usr/local" - this would change our %files section from:
%files
/usr/local/PACKAGE-3.2-1/bin/list
/usr/local/PACKAGE-3.2.1/lib/liblist.so
...
to
%files
/usr/local/bin/list
/usr/local/lib/liblist.so
...
Now our spec file is complete and we can create our RPM using this one simple command: rpmbuild. For our purposes, we'll run:
host # rpmbuild -ba PACKAGE.spec
then we'll kick back and watch the magic happen :) Note that I used the "-ba" option to build both source and binary RPM packages. This created the files /usr/src/packages/SRPMS/PACKAGE-3.2-1.src.rpm and /usr/src/packages/RPMS/x86_64/PACKAGE-3.2-1.x86_64.rpm <--- Note that this directory may be slightly different depending on what OS version of Linux you're running.
Now, you're all set to run "rpm -ivh PACKAGE-3.2-1.x86_64.rpm" and your software package will be installed, and can be manipulated by all the standard "rpm" facilities.
Of course there are tons of other options and additions to the spec file (%post, etc) and rpmbuild command, but this should be enough to get you started. For more specific information, check out the online man pages and chat boards - You'd be surprised at what you can do with this software if you use your imagination :)
Best wishes,
, Mike
linux unix internet technology

