Keep files generated by RPM after rerunning rpm -e - linux

Is it possible to keep RPM content in the filesystem after the uninstallation ?
Basically, I don't want to erase the files generated by the RPM when someone runs rpm -e, but still remove the package from the list of installed RPMs. I want to uninstall my application manually from the server and I cannot find a way to do so.
Thanks in advance.

Specfile creation
From this perspective as a package creator, you can flag files as configurations. John Warbrick at Cambridge Uni has a good rundown of the different file markings you can use in an RPM specfile and how they behave during upgrade.
Files marked %config, if changed, are:
left behind on uninstall but renamed with an .rpmsave extension
untouched on update or reinstall, but the payload copy is installed with an .rpmnew extension
Warbrick does not deal with straight package removal: if a file marked %config is unchanged, erasing the package will remove the file. (Bear in mind that, according to RPM scriptlet ordering, RPM update or reinstall begins with erasing the old package, before the new files are lain down. I.e., the old unchanged config is replaced with the new config.)
It would be an abuse of RPM file classification to mark something a %config that is not really a config. This is important because sysadmins need to be able to trust the package payload. Plus, you probably don't want such a file to be renamed with an extension.
Your best hope then is to create the file during RPM %post. Files copied to the filesystem in %install are checked against the %files list and stored in the RPM database, but files created in %post are not. Again, this an abuse of the RPM spec file format, but if you mention it in the %description and any other documentation, but especially if it's logically expected behavior in the context of your package, you'll maybe get some sympathy.
Existing packages
For sysadmins wanting to remove a package without removing its payload, you use rpm --justdb. First, check the file list:
# rpm -ql $PACKAGE | tee $PACKAGE.payload
[rpm returns list of files, tee saves it in the file $PACKAGE.payload]
# rpm -e --justdb $PACKAGE
(At this stage, you may get a complaint about deps, so repeat with --nodeps if you must.)
And finally, check that the package is gone, but payload is still there:
# rpm -q $PACKAGE
package $PACKAGE is not installed
# ls -l $(<$PACKAGE.payload)
[ls queries list of files saved in $PACKAGE.payload]
(Or for a more reliable ls if filenames contain spaces, which would be unconscionable in RPM.)
# cat $PACKAGE.payload|xargs -d '\n' ls -l
Other observations
Note that for a package created using the method outlined at the top of my answer, attempting to list the files it owns with rpm -ql $PACKAGE will not show those persistent files. Another consequence of throwing down files during %post is that another package which "owns" those files could overwrite them unexpectedly - they're not listed in the RPM database, so they're not protected.
The two methods I've outlined break Best Practices for both RPM package creation and sysadmin. Please be very careful how you use this dangerous "little bit of knowledge". Maybe there's something else you could do to create the desired situation.
(Finally, I know this is a question from four year back. It wasn't answered. It needed answering. Cheers.)

rpm -e --repackage package_name will drop a re-installable copy in /var/spool/repackage. You can extract from that rpm using rpm2cpio if you need those files back individually.

One of the advantages of RPMS is exactly that: you can uninstall (remove)
all the files easily.
If you want to install the files provided by an RPM manually,
simply unpack the RPM as root, with:
cd / &&
rpm2cpio *.rpm | cpio -idmv
It's not a good idea, but you can unpack RPMS like that elsewhere (e.g. under ${HOME}),
and that's very useful. You may need to adjust some environment variables though.
You don't pollute the RPM database but still use the contents of an RPM.
Of course your application may get broken by system updates,
because it is not protected by dependencies.
Anyway this is how you "install" and RPM if you are not root.
Removal is also easy (if installation path chosen suitably).

Related

Allow files from an RPM package to be overwritten by another rpm package

I have an RPM I am making and this is in a very controlled environment so let's also assume it is safe to allow another RPM package to overwrite certain files contained from the original RPM package.
I know from experience if you try to install an RPM package that overwrites another RPM packages file's you get a warning that there is a conflict and the install fails (yes you can do some command line hacking but that is not ideal for the situation).
Is there any way through the original RPM packages spec file that you can specify these files are not part of the package they can be overwritten by another RPM package or is that just strictly prohibited from ever happening?
Is there any way through the original RPM packages spec file that you can specify these files are not part of the package they can be overwritten by another RPM package or is that just strictly prohibited from ever happening?
You can use %ghost directive for this purpose.
http://ftp.rpm.org/max-rpm/s1-rpm-inside-files-list-directives.html

RPM Spec file - how to get rpm package location in %pre script

I am working with RPM package manager for about a month now. Currently I want to use rpm -U to upgrade already existing content from previous RPM execution but I need to know the rpm package location on the file system.
The only way I can think of is searching whole file system for rpm name in %pre script but I would really like to avoid that option. Is there any way to get the path of the rpm package (package can be anywhere on the system) as a variable inside the spec file (%pre and %post script). Hope I explained my issue clearly enough.
Any help or proposal is welcome.
There isn't one location (or path) where a package is installed,
so I'm not sure what you are asking.
The files that are installed by a installed rpm package called "foo"
can be displayed with
rpm -ql foo
There is no common prefix on the paths except "/" in general.

How to "repackage" a RPM file for example cpio2rpm without installing the RPM?

I'm able to extract files from a RPM file, but how do I "rebuild" it, for example cpio2rpm?
I have extracted RPM file using following command.
rpm2cpio theFileName.rpm | cpio –idmv
I have to modify the few web application files like *.php, *.html or .js. These files don’t require any source recompilation. So I would like to replaces or change these files with modification without rebuilding rpm. Since, I need to do this for multiple platforms like Redhat Linux and SUSE, and multiple architecture like 32 and 64 bit OS.
I am expecting to do these changes on only on system and without rebuild rpm and there would not be have target system architecture dependency (like i386, 64).
I am not looking like command rpmbuild –rebuild the.src.rpm since, I don’t have source. I need to be rebuild binary .RPM file(not source .rpm)
I want to do this without source and platform or architecture independent and without using spec file if possible.
Any buddy, could you please suggest any solution or any free tools.
Thank you to all whoever spends time to read and reply to my thread.
You can use rpmrebuild to modify an actual rpm file (it doesn't need to be installed).
Most of the examples for this use complicated inline edit commands to modify known files in particular ways, but you can use a normal editor. I used this to fix a shell script in an rpm file that I didn't have the source for. Call the command as
rpmrebuild -ep theFileName.rpm
This puts you in an editor with the spec file for the RPM. The name of the file will be something like ~/.tmp/rpmrebuild.12839/work/spec.2. If you look in, in this example, ~/.tmp/rpmrebuild.12839/work, you will find all of the files used to make the RPM (in my case, the file was in root/usr/sbin within that directory). So, go to another window, cd to that directory, and edit any files you need to change.
When you have finished editing files, go back to the edit window with the spec file, make any changes you need to that file (I didn't have any, since I wasn't adding or deleting files), save the file, and say "y" to the "Do you want to continue" question. It will then build a new RPM file, and tell you where it has put it (in my case, in ~/rpmbuild/RPMS/x86_64/)
You can repackage an installed RPM (including modified files) using rpmrebuild. http://rpmrebuild.sourceforge.net/
Obviously your binaries (if any) would have to be platform/architecture independent to work on all the OS flavors you're hoping for, but it sounds like if they're just web files that shouldn't be a problem.
Principially you can pack everything you want into a RPM file. Just treat what you have as "source" and write a SPEC file which puts the data where the compiled binaries would normally go.
Concerning RPM, I consider "source" "what I have" and "binary" "what I need to run". Not very exact terminology, but it helps working with RPMs.
Your spec file looks like any other spec file, what concerns the parameters etc. But the code part is different:
[...]
%prep
# Here you either have nothing to do or you already unpack the cpio and possibly modify it.
# %build can be omitted
%install
[ "${buildroot}" != "/" ] && [ -d ${buildroot} ] && rm -rf ${buildroot};
# Here you can either unpack the cpio or copy the data unpacked in %prep.
# Be careful to put it into %{buildroot} or $RPM_BUILD_ROOT.

Run time installation directory of debian package contents

I have a debian package that I built that contains a tar ball of the files, a control file, and a postinst file. Its built using dpkg-deb and it installs properly using dpkg.
The modification I would like to make is to have the installation directory of the files be determined at runtime based on an environment variable that will be set when dpkg -i is run on the deb file. I echo out the environment variable in the postinst script and I can see that its set properly.
My questions:
1) Is it possible to dynamically determine the installation directory at runtime?
2) If its possible how would I go about this? I have read about the rules file and the mypackage.install files but I don't know if either of these would allow me to accomplish this.
I could hack it by copying the files to the target location in the posinst script but I would prefer to do it the right way if possible.
Thanks in advance!
So this is what I found out about this problem over the past couple of weeks.
With prepackaged binaries you can't build a debian package with a destination directory dynamicall determined at runtime. I believe that this might be possible if installing a package that is built from source where you can set the install directory using configure. But in this case since these are embedded Ubuntu machines they don't have make so I didn't pursue such an option. I did work out a non traditional method (hack) for installing that did work. Since debian packages simply contain a tar ball relative to / simply build your package relative to a directory under /tmp. In the postinst script you can then determine where to copy the files from the archive into a permanent location.
I expected that after rebooting and the automatic deletion of the subdirectory under /tmp that dpkg might not know that the file package existed. This wasn't a problem. When I ran 'dpkg -l myapp' it showed as still installed. Updating the package using dpkg/apt-get also worked without a hitch.
What I did find is that if you attempted to remove the package using 'dpkg -r myapp' that dpkg would try and remove /tmp which wasn't good. However /tmp isn't easily removed so it never succeeded. Plus in our situation we never remove packages but instead simply upgrade them.
I eventually had to abandon the universal package due to code differences in the sources resulting in having to recompile per platform but I would have left it this way and it did work.
I tried using --instdir to change the install directory of the package and it does relocate the files but dpkg fails since the dpkg file can't be found relative to the new instdir. Using --instdir is sort of like a chroot. I also tried --admindir and --root in various combinations to see if I could use the dpkg system relative to / but install relocate the files but they didn't work. I guess rpm has a relocate option that works but not Ubuntu.
You can also write a script that runs dpkg-deb with a different environment for 6 times, generating 6 different packages. When you make a modification, you simply have to run your script, and all 6 packages gets generated and you can install them on your machines avoiding postinst hacking!
Why not install to a standard location, and simply use a postinst script to create symbolic links to the desired location? This is much cleaner, and shouldn't break anything in dpk -I.

Why does my hand created deb package fails at install with "unable to create" on files?

I made a perl script that creates a deb binary package from scratch.
I created the data, control, etc.
But when I run dpkg -i on my deb package it complains that it is unable to files from data.
Example:
unable to create '.dpkg-new'(while processing ''): No such file or directory.
I have downloaded some .deb packages to look at and they do not use the preinst script to create the directory structure.
I am thinking I am doing something wrong, I consider having to create my own directories in preinst but it does not seem right... perhaps I am missing something?
Do I have to create directories where my files from data will be copied in the preinst sh, or should dpkg do it and I am doing something wrong?
I had the same problem in a Ruby script I wrote.
I was generating a list of files to pass to tar when building the data.tar.gz archive. When I ungzip and untared the archive manually it would deflate fine, but dpkg would fail.
It turns out that the list of files must also include each directory to create as well.
Note that when I created data.tar.gz I built it with nearly the same options as dpkg-deb/build.c does in the dpkg-1.15.8.11 source.
execlp(TAR, "tar", "-cf", "-", "--format=gnu", "--null", "-T", "-", "--no-recursion", NULL);
Instead I used
IO.popen("gnutar -czf - --format=gnu -T - --no-recursion", "r+")
In addition to what #Arrowmaster said, check the http://www.debian.org/doc/debian-policy/ for some detailed explanation of the files. After you build the package itself, you can check it with lintian tool to see if there is anything obvious you might have missed.
If any one looks for a solution to the problem:
"Build a deb package from an rpm spec file."
Look here http://www.deepnet.cx/debbuild/
I have made my own perl build script much simple then the mentioned one so I can easily maintain it.
Some useful knowledge gained in the process:
0. the deb is an ar archive that contains 3 files, the order of the files is important.
1. the scripts from control.tar.gz must be made executable.
2. it is good to have a preinstall script to make directories if dirs do not exist.
3. sometimes dpkg decides to unzip your zips (this happened if the zip was the only file in the data.tar.gz) so check for that in an postinstall script.
4. when you tar.gz some files be sure to chmod to the dir that contains the directory structure for your tar.
You should not attempt to manually create a .deb binary package by hand. The Debian New Maintainers' Guide covers how to get started creating a Debian package using the correct tools.
Your hand created package may look correct to you but because it is not installing it is obviously flawed in either a minor way that you have not noticed or in a more serious way that is not visible to you (for example most people don't realize a .deb is actually an ar archive).
There are lots of reasons for this. You really need to run:
dpkg -i -D1110 mydeb.deb
And post the result to have any hope of someone being able to solve the problem.

Resources