Hey there,
Special thanks to K.Jans for pointing out the problem with our original script's specificity and for his help in putting together this new version which will address some other RPM's CPIO signatures!
I don't know if we can chalk it up to my enthusiasm or transient thought process, but, of course, the rpm2pkg rpm-to-pkg conversion script that we put out a while ago doesn't perfectly translate every Linux RPM into a usable Solaris Unix datastream pkg file (Mostly because of Solaris being fussy with the pkg names). Unfortunately, there are too many vendors creating too many different versions of the same file type, and using Perl to scrape around inside their CPIO files requires a little bit of modification for every single variation. Not that I'm complaining. I love to do this stuff :)
Still, I will probably write a post on the "process" one of these days (very soon), so that anyone can do it without having to try and read what might be some cryptic scripting ;)
So, today, we have another version of our original RPM to PKG conversion script (which will work with more RPM's, but not the one's the original one worked for, and probably not a lot of other ones ;) for you. If there's any interest in a patch, I can post one (or just email it to you if you request), but it's probably easier to just use one or the other script at this point.
And, here we go again... Enjoy :)
This work is licensed under a
Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License#!/usr/bin/perl
#
# rpm2pkg - creating Solaris pkg files from Linux rpm's
#
# 2008 - Mike Golvach - eggi@comcast.net
#
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#
$rpm=$ARGV[0];
$tmp_dir="dir.$$";
$orig_dir=`pwd`;
mkdir("$tmp_dir");
chdir("$tmp_dir");
## FIX system("rpm2cpio ../$rpm|cpio -dim");
system("rpm2cpio ../$rpm >rpm.cpio.file");
system("cpio -d -i -m <rpm.cpio.file");
## ENDFIX
$proto_list=`find . -print|pkgproto|grep -v prototype`;
open(TMP_FILE, ">>prototype");
print TMP_FILE "i pkginfo\n";
print TMP_FILE $proto_list;
close(TMP_FILE);
# FIX @pkg_info=`strings ../$rpm`;
@pkg_info=`strings rpm.cpio.file`;
$count = 0;
foreach (@pkg_info) {
if ( $_ =~ /^Begin4/ ) {
push(@rpm_info, $_);
$count++;
} elsif ( $_ =~ /(^Copying-policy:|GPL$)/ ) {
last;
} elsif ( $count > 0 ) {
push(@rpm_info, $_);
}
}
$uname_s = `uname -s`;
$uname_r = `uname -r`;
$uname_p = `uname -p`;
$rpm_version = $rpm;
$rpm_version =~ s/\.rpm//;
chomp $uname_s;
chomp $uname_r;
chomp $uname_p;
chomp $rpm_info[1];
chomp $rpm_info[2];
chomp $rpm_info[4];
$rpm_info[1] =~ s/ * *//g;
$rpm_info[2] =~ s/ * *//g;
$rpm_info[4] =~ s/ * *//g;
$rpm_info[1] =~ s/Title://g;
$rpm_info[2] =~ s/Version://g;
open(PKGINFO, ">>pkginfo");
print PKGINFO "SUNW_PRODNAME=\"$uname_s\"\n";
print PKGINFO "SUNW_PRODVERS=\"$uname_r\"\n";
print PKGINFO "SUNW_PKGTYPE=\"usr\"\n";
print PKGINFO "PKG=\"$rpm_info[1]\"\n";
print PKGINFO "NAME=\"$rpm_info[1]\"\n";
print PKGINFO "VERSION=\"$rpm_info[2]\"\n";
print PKGINFO "VSTOCK=\"$rpm_version\"\n";
print PKGINFO "VENDOR=\"GENERIC\"\n";
print PKGINFO "ARCH=\"$uname_p\"\n";
print PKGINFO "EMAIL=\"me@xyz.com\"\n";
print PKGINFO "CATEGORY=\"application\"\n";
print PKGINFO "BASEDIR=/\n";
print PKGINFO "DESC=\"$rpm_info[4]\"\n";
print PKGINFO "PSTAMP=\"Your Name Here\"\n";
print PKGINFO "CLASSES=\"none\"\n";
close(PKGINFO);
system("pkgmk -o -b `pwd` -d /tmp");
system("pkgtrans -o -s /tmp `pwd`/${rpm_info[1]}.pkg $rpm_info[1]");
system("mv ${rpm_info[1]}.pkg ../");
system("cd ../;pwd;rm -r $tmp_dir");
, Mike
linux unix internet technology
Wednesday, April 30, 2008
Creating Solaris Pkg's From RPM's - Take Two
Monday, March 31, 2008
Minor Fix Update - Script To Unpack Solaris Datastream Pkg Files Without Sun's Pkg Utils
Hello again,
Updated 4/4/08 to output pkgproto results to a file named prototype. Originally had it writing to a file named pkgproto. Typo corrected :)
It's been a while since I started looking for a way to finish up our series of articles on RPM and pkg ripping and creating. We started out with creating our own RPM's and did pretty much everything I could think of to those poor packages, all the way through creating RPM's from already installed RPM's and converting RPM's to Solaris pkg's ;)
The only project I had left over (from that bunch) was how to extract the binary contents of Solaris Unix datastream pkg files.
Unfortunately, unlike the "rpm2cpio" command that Solaris includes, they have no regular program for converting a datastream package to an unpackable file (like a cpio or tar), unless you count all the basic pkg commands. What I was looking for was a way to extract a datastream pkg file, and get all the binary contents, without actually installing it. I got no love from Solaris, but I got some free time for myself and eventually figured it out ;)
I've included a script, below, to rip apart a Solaris datastream pkg and create a subdirectory (named the name of the pkg) into which I dump the pkginfo, pkgmap, pkgproto (which I derive from the pkgmap) and all the binary files that the pkg contains. The script, itself, is far from perfect, but if you check it out you can see, fairly easily, how you can manually pull apart a Solaris datastream pkg file and get to the binary contents that you really want (At least, I'm assuming you do - just like me ;)
Note that the version of cpio that comes with Solaris (in the SUNWcsu coreutils package) will complain about garbage bits in your cpio header, when you've clipped off the top of the pkg file. There are really only 2 garbage bits you have to delete (which you can do with vi), but I prefer to use the Gnu version of cpio which will "magically" ignore garbage bits and extract the cpio file no matter what. This version of cpio comes standard on Linux and can be downloaded (in Solaris datastream pkg format) from sunfreeware.com or (in source format, with links to all sorts of OS ports) Gnu's CPIO Download site - just in case you don't want to have to rip apart your Solaris pkg's on Linux (or don't have both OS's at your workplace).
Another strange thing is that Sun's version of cpio won't make directories, by default, that don't exist when you unpack a cpio archive (???) All I'm really saying is: Get the Gnu version - It's free and it'll save you many a gray hair ;)
I've tested today's script on multiple packages from sunfreeware.com and had great success with it working right the first time (assuming that I have Gnu's cpio). The script has broken on a few custom pkg's I've put together myself and can use a lot of work in the "additional" areas (like ensuring pre and post-install scripts get accounted for, depend files get tagged, checkinstall programs are properly extracted, etc). Still, it's a good beginning :)
Hopefully this will be of help to you, if you've been looking all over for something like this, and, almost definitely, can be the starting point for a fully functional Solaris datastream pkg ripper :)
If you want to do this manually, in short terms, just vi the pkg file you're interested in and delete everything up to the final instance of "pkginfo" in the file (after the final "pkgmap" line) and save the rest into another file, which you can manipulate with cpio. Who'd have thought it would end up being that simple? :)
Cheers,
This work is licensed under a
Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License#!/usr/bin/perl
#
# rip_pkg - rip apart Solaris pkg's and get the binaries out
#
# 2008 - Mike Golvach - eggi@comcast.net
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#
if ( $#ARGV != 0 ) {
print "Usage: $0 pkg_file\n";
exit(1);
}
$pkg_name = $ARGV[0];
# check and make sure it's a SVR4 DataStream Pkg
chomp($simple_header_check=`grep -i "package datastream" $pkg_name >/dev/null 2>&1;echo \$?`);
if ( $simple_header_check != 0 ) {
print "This doesn't appear to be a valid SVR4 DataStream pkg file. Exiting...\n";
exit;
}
# Memory Hogging Here - Until This Cold Quits Me And I Can Think My Way Out Of This ;)
open(PKG, "<$pkg_name");
@pkg_file = <PKG>;
close(PKG);
# Split out header information and kludgey cpio file with binary contents
$header_end = 0;
$cpio_start = 0;
open (P_HEADERS, ">$pkg_name.headers");
foreach $line (@pkg_file) {
if ( $header_end == 0 && $line =~ /TRAILER/ && $line =~ /pkginfo/ ) {
print P_HEADERS $line;
$header_end = 1;
} elsif ( $header_end == 1 && $line =~ /pkginfo/ ) {
print P_HEADERS $line;
close(P_HEADERS);
$cpio_start = 1;
open(P_CPIO, ">$pkg_name.cpio");
} elsif ( $cpio_start == 0 ) {
print P_HEADERS $line;
} elsif ( $cpio_start == 1 ) {
print P_CPIO $line;
} else {
print STDERR "WTF?\n";
}
}
close(P_CPIO);
open(P_HEADERS, "<$pkg_name.headers");
@p_headers = <P_HEADERS>;
close(P_HEADERS);
$output_dir = 0;
$pkginfo_start = 0;
$pkginfo_seek = 0;
$pkgmap_start = 0;
foreach $p_head (@p_headers) {
if ( $output_dir eq 1 && $pkginfo_seek == 0 ) {
$output_dir = $p_head;
$output_dir =~ s/^(\w+)\W*.*$/$1/;
chomp($output_dir);
$pkginfo_seek = 1;
} elsif ( $output_dir eq 0 && $p_head =~ /datastream/i ) {
$output_dir = 1;
} elsif ( $output_dir eq 0 && $pkginfo_start == 0 ) {
next;
} elsif ( $output_dir ne 0 && $p_head =~ /pkgmap/ ) {
$pkgmap_start = 1;
$pkginfo_start = 0;
} elsif ( $pkgmap_start == 1 && $p_head =~ /pkginfo/ ) {
chomp($p_head);
push(@pkgmap, $p_head);
last;
} elsif ( $output_dir ne 0 && $p_head =~ /pkginfo.*PKG=/ ) {
$pkginfo_start = 1;
} elsif ( $output_dir ne 0 && $pkgmap_start == 1 ) {
chomp($p_head);
push(@pkgmap, $p_head);
} elsif ( $output_dir ne 0 && $pkginfo_start == 1 ) {
chomp($p_head);
push(@pkginfo, $p_head);
} else {
print "WTF NOTHING MATCHED\n OD $output_dir PST $pkginfo_start PS $pkginfo_seek PMST $pkgmap_start\n$p_head\n";
}
}
mkdir("$output_dir");
chdir("$output_dir");
open(PKGINFO_OUT, ">>pkginfo");
foreach $info (@pkginfo) {
print PKGINFO_OUT "$info\n";
}
open(PKGMAP_OUT, ">>pkgmap");
foreach $map (@pkgmap) {
print PKGMAP_OUT "$map\n";
}
open(PROTO_OUT, ">>prototype");
foreach $proto (@pkgmap) {
@proto = split(" ", $proto);
print PROTO_OUT "$proto[1] $proto[2] $proto[3] $proto[4] $proto[5] $proto[6]\n";
}
system("cpio -iv <../$pkg_name.cpio >/dev/null 2>&1");
chdir("reloc");
system("tar cpf - *|(cd ../;tar xpf -)");
chdir("../");
system("rm -r reloc");
chdir("../");
unlink "$pkg_name.headers";
unlink "$pkg_name.cpio";
, Mike
linux unix internet technology
Saturday, March 15, 2008
Converting Linux RPM's Into Solaris Pkg Files
Hey there,
As this week wraps up, I thought I'd put out the last few things I've been toying around with. Today, we've got a Perl script for you that will take an RPM (From Linux) and convert it to a Solaris datastream pkg file. Of course, we've got the opposite (just like we have the opposite of our post on creating Solaris pkg files from already installed content, which we'll post in the next few days. That might be a more useful script than this one (you might actually "need" to recreate a Linux RPM from what's on your box more often), but I thought this script was kind of cool :)
Basically, you can take any Linux RPM (I tested against RedHat AS and SUSE 9), feed it to this script, like so:
host # ./rpm2pkg PROGRAM-3.2-1.rpm
and end up with your own valid Solaris pkg file named:
PROGRAM-3.2-1.pkg
My thought was that this might be useful, since one of the commands used inside it (rpm2cpio) is already included in Solaris 9 and 10. For architecture-independent, and binary compatible, programs, there obviously exists a need to convert Linux RPM's to a cpio archive that can then be extracted to the local filesystem on a Solaris machine. In my mind, the logical next step would be to skip ahead and create a valid Solaris datastream pkg file from that cpio output. This way, the process could be completed once and then distributed easily as a single pkg installation file to all of your Solaris servers:)
The script works, as mentioned above, by using rpm2cpio to extract the Linux RPM's contents and then using the "strings" command on the actual RPM to extract all the header information that we require to seed the "pkginfo" file. The prototype file is the easiest necessary pkgmk file to create since you just have to use find and pkgproto on the extracted rpm2cpio output.
If you want to be able to tweak this more to your liking, there's a lot more information about the Solaris pkg making process in our previous posts on building Solaris pkg files quickly and, more theoretically, what you need to know to create your own Solaris pkg files.
Enjoy the script and have fun trying to get Linux binaries to run on your Solaris box (Hint: You're success rate will be much greater on Solaris 10, since they're finally buying into "open source" :)
Best wishes,
This work is licensed under a
Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License#!/usr/bin/perl
#
# rpm2pkg - creating Solaris pkg files from Linux rpm's
#
# 2008 - Mike Golvach - eggi@comcast.net
#
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#
$rpm=$ARGV[0];
$tmp_dir="dir.$$";
$orig_dir=`pwd`;
mkdir("$tmp_dir");
chdir("$tmp_dir");
system("rpm2cpio ../$rpm|cpio -dim");
$proto_list=`find . -print|pkgproto|grep -v prototype`;
open(TMP_FILE, ">>prototype");
print TMP_FILE "i pkginfo\n";
print TMP_FILE $proto_list;
close(TMP_FILE);
@pkg_info=`strings ../$rpm`;
$count = 0;
foreach (@pkg_info) {
if ( $_ =~ /\# \@\(\#\)BegWS/ ) {
push(@rpm_info, $_);
$count++;
} elsif ( $_ =~ /\# \@\(\#\)EndWS/ ) {
last;
} elsif ( $count > 0 ) {
push(@rpm_info, $_);
}
}
$uname_s = `uname -s`;
$uname_r = `uname -r`;
$uname_p = `uname -p`;
$pkg_name = $rpm;
$pkg_name =~ s/\.rpm//;
chomp $uname_s;
chomp $uname_r;
chomp $uname_p;
chomp $rpm_info[1];
chomp $rpm_info[2];
chomp $rpm_info[5];
chomp $rpm_info[12];
open(PKGINFO, ">>pkginfo");
print PKGINFO "SUNW_PRODNAME=\"$uname_s\"\n";
print PKGINFO "SUNW_PRODVERS=\"$uname_r\"\n";
print PKGINFO "SUNW_PKGTYPE=\"usr\"\n";
print PKGINFO "PKG=\"$pkg_name\"\n";
print PKGINFO "NAME=\"$rpm_info[2]\"\n";
print PKGINFO "VERSION=\"$rpm_info[5]\"\n";
print PKGINFO "VENDOR=\"$rpm_info[1]\"\n";
print PKGINFO "ARCH=\"$uname_p\"\n";
print PKGINFO "EMAIL=\"me@xyz.com\"\n";
print PKGINFO "CATEGORY=\"application\"\n";
print PKGINFO "BASEDIR=/\n";
print PKGINFO "DESC=\"$rpm_info[12]\"\n";
print PKGINFO "PSTAMP=\"Your Name Here\"\n";
print PKGINFO "CLASSES=\"none\"\n";
close(PKGINFO);
system("pkgmk -o -b `pwd` -d /tmp");
system("pkgtrans -o -s /tmp `pwd`/${pkg_name}.pkg $pkg_name");
system("mv ${pkg_name}.pkg ../");
system("cd ../;pwd;rm -r $tmp_dir");
, Mike
linux unix internet technology

