PackagingDrafts/UsingAlternatives

Existing guideline
None.

Proposal
Following change to Packaging Guidelines is proposed: Add a section Use of alternatives which would read:

What are alternatives
Alternatives provide means for parallel installation of packages which provide the same functionality by maintaining sets of symlinks (one per package) pointing to alternativized files like this: For more information, see  manpage.

Recommended usage
Alternatives can be used to allow parallel installation of software that can be used as a drop-in replacement and functions with sufficient similarity that users and other programs would, within reason, not need to know which variant is currently installed (for example: the various MTAs which all provide ). Selection of which of the parallel-installed packages to use for a given alternativized file can only be done system-wide by a root-level user. Alternatives are not recommended to facilitate parallel installation of software whose selection should be done by users (for example: the various MPI environments).

How to use alternatives
If a package is using alternatives, the files which would otherwise conflict must be installed with an appropriate suffix (for example:  instead of  ), the original locations must be touched (for example:  ), the links set up by alternatives must be listed as %ghost in the file list and proper Requires: must be added, like in the examples below.

Putting the alternativized files in the file list ensures that they are owned by respective packages, which means that commands like: all work properly. Using %ghost for this purpose allows using globs and generated file lists.
 * rpm -qf /usr/bin/foo
 * yum install /usr/bin/foo
 * repoquery --whatprovides /usr/bin/foo

Examples
Example from antlr.spec: Requires(post): %{_sbindir}/update-alternatives Requires(postun): %{_sbindir}/update-alternatives ... %install ... touch %{buildroot}%{_bindir}/antlr

%post %{_sbindir}/update-alternatives --install %{_bindir}/antlr \ %{name} %{_bindir}/antlr-java 10

%postun if [ $1 -eq 0 ] ; then %{_sbindir}/update-alternatives --remove %{name} %{_bindir}/antlr-java fi ... %files ... %ghost %{_bindir}/antlr %{_bindir}/antlr-java

And a more complex example of alternatives invocation from sendmail.spec, slightly edited: Requires(post): %{_sbindir}/update-alternatives Requires(postun): %{_sbindir}/update-alternatives Requires(preun): %{_sbindir}/update-alternatives ... %install ... mv %{buildroot}%{_sbindir}/sendmail %{buildroot}%{_sbindir}/sendmail.sendmail touch %{buildroot}%{_sbindir}/sendmail for i in mailq newaliases rmail; do	mv %{buildroot}%{_bindir}/$i %{buildroot}%{_bindir}/$i.sendmail touch %{buildroot}%{_bindir}/$i done mv %{buildroot}%{_mandir}/man1/mailq.1 %{buildroot}%{_mandir}/man1/mailq.sendmail.1 touch %{buildroot}%{_mandir}/man1/mailq.1 mv %{buildroot}%{_mandir}/man1/newaliases.1 %{buildroot}%{_mandir}/man1/newaliases.sendmail.1 touch %{buildroot}%{_mandir}/man1/newaliases.1 mv %{buildroot}%{_mandir}/man5/aliases.5 %{buildroot}%{_mandir}/man5/aliases.sendmail.5 touch %{buildroot}%{_mandir}/man5/aliases.5 mv %{buildroot}%{_mandir}/man8/sendmail.8 %{buildroot}%{_mandir}/man8/sendmail.sendmail.8 touch %{buildroot}%{_mandir}/man8/sendmail.8
 * 1) rename files for alternative usage

%postun if [ "$1" -ge "1" ]; then if [ "`readlink %{_sysconfdir}/alternatives/mta`" == "%{_sbindir}/sendmail.sendmail" ]; then %{_sbindir}/alternatives --set mta %{_sbindir}/sendmail.sendmail fi fi

%post %{_sbindir}/update-alternatives --install %{_sbindir}/sendmail mta %{_sbindir}/sendmail.sendmail 90 \ --slave %{_bindir}/mailq mta-mailq %{_bindir}/mailq.sendmail \ --slave %{_bindir}/newaliases mta-newaliases %{_bindir}/newaliases.sendmail \ --slave %{_bindir}/rmail mta-rmail %{_bindir}/rmail.sendmail \ --slave /usr/lib/sendmail mta-sendmail /usr/lib/sendmail.sendmail \ --slave %{_sysconfdir}/pam.d/smtp mta-pam %{_sysconfdir}/pam.d/smtp.sendmail \ --slave %{_mandir}/man8/sendmail.8.gz mta-sendmailman %{_mandir}/man8/sendmail.sendmail.8.gz \ --slave %{_mandir}/man1/mailq.1.gz mta-mailqman %{_mandir}/man1/mailq.sendmail.1.gz \ --slave %{_mandir}/man1/newaliases.1.gz mta-newaliasesman %{_mandir}/man1/newaliases.sendmail.1.gz \ --slave %{_mandir}/man5/aliases.5.gz mta-aliasesman %{_mandir}/man5/aliases.sendmail.5.gz \ --initscript sendmail ...
 * 1) Set up the alternatives files for MTAs.

%preun if [ $1 = 0 ]; then %{_sbindir}/update-alternatives --remove mta %{_sbindir}/sendmail.sendmail fi ...

%files ... %ghost %{_sbindir}/sendmail %ghost %{_bindir}/mailq %ghost %{_bindir}/newaliases %ghost %{_bindir}/rmail %ghost /usr/lib/sendmail %ghost %{_sysconfdir}/pam.d/smtp %ghost %{_mandir}/man8/sendmail.8.gz %ghost %{_mandir}/man1/mailq.1.gz %ghost %{_mandir}/man1/newaliases.1.gz %ghost %{_mandir}/man5/aliases.5.gz

%{_sbindir}/sendmail.sendmail %{_bindir}/mailq.sendmail %{_bindir}/newaliases.sendmail %{_bindir}/rmail.sendmail /usr/lib/sendmail.sendmail %config(noreplace) %{_sysconfdir}/pam.d/smtp.sendmail %{_mandir}/man8/sendmail.sendmail.8.gz %{_mandir}/man1/mailq.sendmail.1.gz %{_mandir}/man1/newaliases.sendmail.1.gz %{_mandir}/man5/aliases.sendmail.5.gz

%attr(0755,root,root) %{_initrddir}/sendmail

Motivation
Current usage of alternatives is inconsistent, and rpm -qf /some/file will often say the file is unowned, even if it's been created by some package, which is especially misleading and annoying in case of binaries.

Existing practice
Packages using this solution:
 * antlr
 * cdrkit
 * classpathx-jaf
 * classpathx-mail
 * ettercap
 * jakarta-commons-dbcp
 * java-1.5.0-gcj
 * OpenEXR_Viewers
 * pinentry
 * saxon
 * xalan-j2
 * xemacs
 * xerces-j2

Packages that need fixing:
 * cups
 * emacs
 * esmtp
 * exim
 * fedora-usermgmt
 * gcin
 * gridengine
 * ibus
 * imsettings
 * java-1.6.0-openjdk
 * kinput2
 * libextractor
 * mx4j
 * nabi
 * openmpi
 * postfix
 * scim
 * sendmail
 * ssmtp
 * tomcat5
 * uim
 * unison213
 * unison227
 * ushare