Suppose packages I'm building for myprog1 and myprog2 are to install in /usr/lib/mysystem/myprog1/ and /usr/lib/mysystem/myprog2/
According to some distros' documentation, such in the case of OpenSUSE, both packages must own the shared directory. But how is that accomplished in the .spec files? Is the following correct?
%files
/usr/lib/mysystem
or do I need to do
%files
%dir /usr/lib/mysystem
/usr/lib/mysystem/myprog<1|2>
Usually only one package owns a given directory. On a typical system, there will be a package such as "filesystem" which may own things such as /bin. In the case of the filesystem package on Red Hat and OpenSUSE, that package owns /usr/bin but none of the files within that directory.
You could do that, by making a wrapper-package which owns things that are shared across your applications, and making it a dependency (Requires) of the applications which install into those directories.
To see what actually owns something with rpm, you can use the -qf options, e.g.,
rpm -qf /usr/lib/mysystem/myprog
The command works for directories as well as files.
The documentation for %dir and %files is the place to start when deciding how to make a package own a directory. In Maximum RPM: Taking the Red Hat Package Manager to the Limit, chapter 13 Directives For the %files list, it says:
As we mentioned in the section called The %files List, if a directory is specified in the %files list, the contents of that directory, and the contents of every directory under it, will automatically be included in the package
The way to get around this, is to use the %dir directive. By adding this directive to the line containing the directory, RPM will package only the directory itself, regardless of what files are in the directory at the time the package is created. Here's an example of %dir in action.
%dir /usr/blather
So the latter of the suggested cases follows the documentation. However, as a check on whether the syntax is correct (even if the rpm happens to build) it is good practice to examine the list of pathnames.
Investigating Fedora 21 to find packages for which rpm -qf shows the same directory finds several. For example, initscripts and chkconfig use the %dir directive to do this:
%dir /etc/rc.d
%dir /etc/rc.d/rc[0-9].d
%dir /etc/rc.d/init.d
in initscripts spec-file, and
/etc/rc.d
/etc/rc.d/init.d
/etc/rc[0-6].d
/etc/rc.d/rc[0-6].d
in chkconfig spec-file. However, the initscripts package requires /sbin/chkconfig, which is provided by the chkconfig package. Because of that dependency, chkconfig is the actual owner of the directory.
That depends, especially if the packages for program1 and program2 are built from one source or form completely different sources.
If they come from one source, you have to differentiate in a more sophisticated way:
%files program1
%dir /usr/lib/mysystem
/usr/lib/mysystem/program1
%files program2
%dir /usr/lib/mysystem
/usr/lib/mysystem/program2
If you build them separately, you can just do
%files programX
/usr/lib/mysystem
if you work with a clean buildroot which nevertheless only contains the files created by your package.
But it doesn't hurt to do
%files programX
%dir /usr/lib/mysystem
/usr/lib/mysystem/programX
as well.
If you have several such packages, you could even create a common package which owns that directory and which as well provides other requirements if you have such. It is then sufficient to require this "parent package", "company package" or how you want to name it.
Then it is enough to do
Requires: mysystemcompanypackage
...
%files
/usr/lib/mysystem/program1
Related
I'm having some issues installing a script into /usr/sbin from a cmake script. In my packaging.cmake I have
install(FILES "${CMAKE_SOURCE_DIR}/kpcmdctrl" DESTINATION /usr/sbin COMPONENT kptester
PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ)
and in the generated spec file:
%files
%defattr(-,root,root,-)
%dir "/opt/mycomp"
%dir "/opt/mycomp/kptester_prog"
%dir "/opt/mycomp/kptester_prog/bin"
"/opt/mycomp/kptester_prog/bin/kptester"
%dir "/opt/mycomp/kptester_prog/etc"
%dir "/usr/sbin"
%config "/usr/sbin/kpcmdctrl"
when I run yum localinstall kptester-0.0.1-1.x86_64.rpm I get the following error:
Error: Transaction test error:
file /usr/sbin from install of kptester-0.0.1-1.x86_64 conflicts with file from package filesystem-3.8-6.el8.x86_64
I've tried installing the script in other places such as /usr/bin and it works without issue. I've checked the package listing for filesystem-3.8-6.el8.x86_6 here and I can't see any reason for it to complain?
Am I missing something obvious or is /usr/sbin a special directory?
Posting my own solution in case anyone else comes across this problem. The problem was that the RPM was trying to own the system folder e.g. /usr/sbin. You can see this from the spec file I posted in the question: %dir "/usr/sbin"
There is an option in cmake to tell it not do to this:
set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "/usr/sbin")
or if you have more than one system folder:
list(APPEND CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "/usr/sbin")
The new spec file doesn't have the system folder listed as a directory and install works as expected.
Consider a SPEC file containing:
%install
install -m u=rwx,g=rx,o= -D bin/blah.jar ${RPM_BUILD_ROOT}%{_libexecdir}/foo/blah.jar
Then in the %files section, the permissions are not changed (say, %defattr(-,bubba,users,-)).
Installing the RPM results in blah.jar having permissions 644 instead of 640. Indeed, no matter what permissions are used in the install command, they're reset to the default 640. I've found that the cause is the jar repacking, as permissions are maintained if I disable repacking by adding %define __jar_repack %{nil} to the SPEC file.
This is a nasty bug of the repacker.
How do I get both repacking to work and the permissions to be preserved (and I mean preserved, not setting them instead in the %files section, as then I'd have to mention individual files not only in %install but in %files as well, rather than just whole directories in the latter)?
I created a binary package with this command:
dpkg-deb --build -z9 -Zlzma $(DEB_SRC_DIR) $(DEB_DEST_DIR)
and install it on my Ubuntu 12.04 with this command:
sudo dpkg -i /path/to/package
The contents of the package I think are irrelevant.
Despite the sudo command the files in the installation directory belong to the current user and not to root as I expected.
How can I fix that?
Try to run the dpkg-deb command with fakeroot:
`fakeroot dpkg-deb ...`
(This will only help if the files in the source directory already have the correct ownership, which they probably dont. The problem you're actually trying to solve here, is to create an archive with files in it that belong to user root, which is where fakeroot theoretically helps.)
Let me say though, that what you are doing is not the best way for creating a binary package (far from it).
Instead, create a debian/ directory with dh_make (from the dh-make package), and edit the control file and changelog accordingly. You also need a file debian/install that lists what files you are installing and where they should go. There are various guides on the net (and on Stack Overflow) that explain this process. For example, look at the Debian New Maintainers' Guide.
You can then use dpkg-buildpackage to create a real, standard-conforming Debian package with your files in a reproducible way.
dpkg-deb is a low-level tool for manipulating existing deb files; it's not meant to be used for package creation.
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).
In the process of building an RPM package, I have to specify the BuildRoot and later will be used in %install which invovles $RPM_BUILD_ROOT. I always think that $RPM_BUILD_ROOT is the fake installation for RPM to perform packaging. Then, at install time using the RPM package, it will install into actual location. For example:
$RPM_BUILD_ROOT/usr/bin
I thought that $RPM_BUILD_ROOT is for the packaging process only, and in some ways RPM can distinguish the $RPM_BUILD_ROOT and the actual install location when the user performs "rpm -ivh package.rpm" will be /usr/bin.
But recently upon reading some documents, it is suggested that $RPM_BUILD_ROOT is the actual location which will be installed, and the $RPM_BUILD_ROOT is specified by user with the setting of environment variable $RPM_BUILD_ROOT in order to let the users install the package in their desire locations. Otherwise, $RPM_BUILD_ROOT will be null and it will install into the default location. In the above case, it is /usr/bin . Thus, $RPM_BUILD_ROOT is not just for packaging or "fake installation" process, but is a way for user to define install location, similar to select folder location in Windows.
I don't know my thinking is correct or not. Can someone please verify? Thanks in advance.
$RPM_BUILD_ROOT (or the equivalent %{buildroot} SPEC file macro) always holds the directory under which RPM will look for any files to package. The RPM scripts (e.g. the script that compresses the manual pages) will also use that value to know where to look for the files that were just installed. Normally, this value will be non-empty and contain a location away from the system directories - usually somewhere under /tmp or /var/tmp.
The author of the SPEC file is expected to make sure that make install (or whatever installer the software in question is using) will place any files under $RPM_BUILD_ROOT, with the same hierarchy that should be used when the software is finally installed. E.g. to have RPM install ls in /bin/ls, the %install SPEC file section should make sure that ls is placed in $RPM_BUILD_ROOT/bin/ls.
The author of the SPEC file is also expected to use the BuildRoot: tag to specify a proper location. Alternatively, the build system could have an rpmrc RPM configuration file with a proper entry. In any case the build root should be set, so that:
Normal users will be able to build the source package.
Should the superuser ever build the source package, the build process will not clobber any system files, unless the superuser installs the resulting binary package. And yes, there may be a good reason to build some packages as root - for example, running the full glibc testsuite requires root privileges for some tests.
That said, RPM can and will build a package with an empty build root variable. In that case both the build install and the final destination locations will coincide. A potential call to e.g. make install will use the default locations, thus clobbering the system files under e.g. /usr/lib if run with sufficient privileges. Additionally, having /usr/bin/* in your %files section will happily pull the whole contents of the build host /usr/bin/ directory into your binary package.
Bottom line:
Never use an empty build root.
Do not build packages as root unless there is absolutely no other way.
the file ~/.rpmmacros defines the paths per user:
%_topdir %(echo $HOME)/rpmbuild
%_tmppath %{_topdir}/tmp
and one can also define them with rpmbuild command line parameters:
rpmbuild --define '_topdir /home/username/rpmbuild'